Skip to content

Commit

Permalink
Merge pull request #41 from walt-id/40-support-for-multiple-nft-ecosy…
Browse files Browse the repository at this point in the history
…stems-in-authorization-flow

refactoring and impl of support for multiple ecosystems in authorizat…
  • Loading branch information
khemiriwalid authored Mar 16, 2023
2 parents 325e738 + 40d1974 commit 6dc00fa
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 208 deletions.
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 120
tab_width = 4
tab_width = 2
trim_trailing_whitespace = true
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
Expand Down
35 changes: 28 additions & 7 deletions config/idp-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,37 @@
{
"scope": [ "award" ],
"claim": "awd",
"chain": "POLYGON",
"smartContractAddress": "0x9bc4d80c7b77ecc7107eac3961cb1dd98930f2b2",
"factorySmartContractAddress": "",
"trait": "award"
"claimMappings": {
"EVM": {
"nftTokenConstraint": {
"chain": "POLYGON",
"smartContractAddress": "0x9bc4d80c7b77ecc7107eac3961cb1dd98930f2b2",
"factorySmartContractAddress": ""
},
"trait": "award"
}
}
}
],
"default_nft_token_claim": {
"chain": "TESTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "demo.khaled_lightency1.testnet"
"ecosystems": [ "EVM", "TEZOS", "NEAR" ],
"nftTokenContraints": {
"EVM": {
"chain": "POLYGON",
"factorySmartContractAddress": "",
"smartContractAddress": "0x21dd9b1913d84ab295fdf19834b0b6824a5912ca"
},
"TEZOS": {
"chain": "GHOSTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "KT1Rc59ukgW32e54aUdYqVzTM9gtHrA4JDYp"
},
"NEAR": {
"chain": "TESTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "demo.khaled_lightency1.testnet"
}
}
},
"default_vp_token_claim": {
"presentation_definition": {
Expand Down
28 changes: 20 additions & 8 deletions src/main/kotlin/id/walt/idp/config/ClaimConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package id.walt.idp.config
import com.jayway.jsonpath.JsonPath
import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.oauth2.sdk.Scope
import id.walt.idp.nfts.ChainEcosystem
import id.walt.idp.nfts.NFTManager
import id.walt.idp.nfts.NftTokenClaim
import id.walt.idp.nfts.NftTokenConstraint
import id.walt.idp.oidc.OIDCManager
import id.walt.idp.oidc.ResponseVerificationResult
import id.walt.model.oidc.VpTokenClaim
Expand Down Expand Up @@ -36,19 +39,28 @@ class VCClaimMapping(
get() = OIDCManager.AuthorizationMode.SIOP
}

data class NFTClaimMappingDefinition(
val nftTokenConstraint: NftTokenConstraint,
val trait: String
)

class NFTClaimMapping(
scope: Set<String>,
claim: String,
val chain: String,
val smartContractAddress: String,
val factorySmartContractAddress: String,
val trait: String
val claimMappings: Map<String, NFTClaimMappingDefinition>
) : ClaimMapping(scope, claim) {
override fun fillClaims(verificationResult: ResponseVerificationResult, claimBuilder: JWTClaimsSet.Builder) {
val attribute =
verificationResult.nftresponseVerificationResult?.metadata?.evmNftMetadata?.attributes?.firstOrNull { a -> a.trait_type == trait }
?: throw BadRequestResponse("Requested nft metadata trait not found in verification response")
claimBuilder.claim(trait, attribute.value)
val mappingDefinition = verificationResult.nftresponseVerificationResult?.ecosystem?.let {
claimMappings[it.name]
} ?: throw BadRequestResponse("No mapping definition found for the given ecosystem")

val claimValue = when(verificationResult.nftresponseVerificationResult.ecosystem) {
ChainEcosystem.EVM -> verificationResult.nftresponseVerificationResult.metadata?.evmNftMetadata?.attributes?.firstOrNull { a -> a.trait_type == mappingDefinition.trait }?.value
ChainEcosystem.TEZOS -> verificationResult.nftresponseVerificationResult.metadata?.tezosNftMetadata?.attributes?.firstOrNull { a -> a.name == mappingDefinition.trait }?.value
ChainEcosystem.NEAR -> verificationResult.nftresponseVerificationResult.metadata?.nearNftMetadata?.metadata?.let { NFTManager.getNearNftAttributeValue(it, mappingDefinition.trait) }
}?: throw BadRequestResponse("Requested nft metadata trait not found in verification response")

claimBuilder.claim(mappingDefinition.trait, claimValue)
}

override val authorizationMode: OIDCManager.AuthorizationMode
Expand Down
11 changes: 10 additions & 1 deletion src/main/kotlin/id/walt/idp/nfts/NFTClaims.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import id.walt.nftkit.services.Chain
import net.minidev.json.JSONObject
import net.minidev.json.parser.JSONParser

data class NftTokenClaim(
data class NftTokenConstraint(
@Json(serializeNull = false)
val chain: Chain?,
@Json(serializeNull = false)
Expand All @@ -16,6 +16,15 @@ data class NftTokenClaim(
val factorySmartContractAddress: String?,
)

enum class ChainEcosystem {
EVM, TEZOS, NEAR
}

data class NftTokenClaim(
val ecosystems: Set<ChainEcosystem>,
val nftTokenContraints: Map<String, NftTokenConstraint>
)

class NFTClaims(
@Json(serializeNull = false) val nft_token: NftTokenClaim? = null,
) : OIDCClaimsRequest() {
Expand Down
124 changes: 42 additions & 82 deletions src/main/kotlin/id/walt/idp/nfts/NFTController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,105 +44,65 @@ object NFTController {
val sessionId = ctx.queryParam("session") ?: throw BadRequestResponse("Session not specified")
val message = ctx.queryParam("message") ?: throw BadRequestResponse("Message not specified")
val signature = ctx.queryParam("signature") ?: throw BadRequestResponse("Signature not specified")
val chain = ctx.queryParam("chain") ?: throw BadRequestResponse("Chain not specified")
val ecosystem = ctx.queryParam("ecosystem")?.let { ChainEcosystem.valueOf(it.toUpperCase()) } ?: throw BadRequestResponse("Ecosystem not specified")


val session = OIDCManager.getOIDCSession(sessionId)
if (session == null) {
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid or no session was set.")
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid or no session was set.", ecosystem)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}

if (!OIDCManager.AuthorizationMode.NFT.equals(session?.authorizationMode)) {
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid callback.")
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid callback.", ecosystem)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}

if ("EVM".equals(chain)){
var address = ""
val siwxResult = when(ecosystem) {
ChainEcosystem.EVM -> {
val request = SiweRequest(message, signature)
val eip4361msg = Eip4361Message.fromString(request.message)

if (!SiweManager.messageAndSignatureVerification(session!!, message, signature)) {
val uri = NFTManager.generateErrorResponseObject(sessionId, eip4361msg.address, "Invalid signature.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val result = NFTManager.verifyNftOwnershipResponse(sessionId, eip4361msg.address)
if (IDPConfig.config.claimConfig?.default_nft_policy == null) {
throw BadRequestResponse("Missed policy configuration")
}
if (result.isValid && IDPConfig.config.claimConfig?.default_nft_policy!!.withPolicyVerification!!) {
val policyVerification = NFTManager.verifyNftMetadataAgainstPolicy(result.metadata!!)
if (policyVerification) {
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val uri = NFTManager.generateErrorResponseObject(sessionId, eip4361msg.address, "Invalid policy verification.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
} else {
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
}
}else if("Tezos".equals(chain)){
val publicKey= SiwtManager.getPublicKey(message)
val address= SiwtManager.getAddress(message)
if(!SiwtManager.verifySignature(session!!,message, publicKey, signature)){
val uri = NFTManager.generateErrorResponseObject(sessionId, address, "Invalid signature.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}else{
val result = NFTManager.verifyTezosNftOwnership(sessionId, address)
if(result.isValid && IDPConfig.config.claimConfig?.default_nft_policy!!.withPolicyVerification!!){
val policyVerification = NFTManager.verifyNftMetadataAgainstPolicy(result.metadata!!)
if (policyVerification) {
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid policy verification.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
}else{
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}

}
}
else if("TESTNET".equals(chain)){
address = Eip4361Message.fromString(request.message).address
SiweManager.messageAndSignatureVerification(session!!, message, signature)
}
ChainEcosystem.TEZOS -> {
val publicKey = SiwtManager.getPublicKey(message)
address = SiwtManager.getAddress(message)
SiwtManager.verifySignature(session!!,message, publicKey, signature)
}
ChainEcosystem.NEAR -> {
val publicKey = SiwnManager.getPublicKey(message)
print( "is the public key" + publicKey )
val address = SiwnManager.getAddress(message)
print("is addresse"+address)
address = SiwnManager.getAddress(message)
print("is address " + address)
SiwnManager.verifySignature(session!!, message, publicKey, signature)
}
}

if (!SiwnManager.verifySignature(session!!, message, publicKey, signature)) {
val uri = NFTManager.generateErrorResponseObject(sessionId, address, "Invalid signature.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
else{
val result = NFTManager.verifyNearNftOwnership(sessionId, address)
if (result.isValid && IDPConfig.config.claimConfig?.default_nft_policy!!.withPolicyVerification!!){
val policyVerification = NFTManager.verifyNftMetadataAgainstPolicy(result.metadata!!)
if (policyVerification) {
val responseVerificationResult =
ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val uri = NFTManager.generateErrorResponseObject(sessionId, "", "Invalid policy verification.")
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
}else{
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
if(!siwxResult) {
val uri = NFTManager.generateErrorResponseObject(sessionId, address, "Invalid signature.", ecosystem)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val result = NFTManager.verifyNftOwnershipResponse(sessionId, address, ecosystem)
if (IDPConfig.config.claimConfig?.default_nft_policy == null) {
throw BadRequestResponse("Missed policy configuration")
}
if (result.isValid && IDPConfig.config.claimConfig?.default_nft_policy!!.withPolicyVerification!!) {
val policyVerification = NFTManager.verifyNftMetadataAgainstPolicy(result.metadata!!)
if (policyVerification) {
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
} else {
val uri = NFTManager.generateErrorResponseObject(sessionId, address, "Invalid policy verification.", ecosystem)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
} else {
val responseVerificationResult = ResponseVerificationResult(siopResponseVerificationResult = null, result)
val uri = OIDCManager.continueIDPSessionResponse(sessionId, responseVerificationResult)
ctx.status(HttpCode.FOUND).header("Location", uri.toString())
}
}

}


Expand Down
Loading

0 comments on commit 6dc00fa

Please sign in to comment.