github.com/Axway/agent-sdk@v1.1.101/pkg/authz/oauth/clientmetadatabuilder.go (about) 1 package oauth 2 3 import ( 4 "crypto/x509" 5 "encoding/base64" 6 "encoding/json" 7 "encoding/pem" 8 "fmt" 9 10 "github.com/Axway/agent-sdk/pkg/config" 11 "github.com/Axway/agent-sdk/pkg/util" 12 jwkcert "github.com/lestrrat-go/jwx/v2/cert" 13 "github.com/lestrrat-go/jwx/v2/jwk" 14 ) 15 16 var grantTypeWithRedirects = map[string]bool{GrantTypeAuthorizationCode: true, GrantTypeImplicit: true} 17 18 // ClientBuilder - Builder for IdP client representation 19 type ClientBuilder interface { 20 SetClientName(string) ClientBuilder 21 22 SetScopes([]string) ClientBuilder 23 SetGrantTypes([]string) ClientBuilder 24 SetResponseType([]string) ClientBuilder 25 SetTokenEndpointAuthMethod(tokenAuthMethod string) ClientBuilder 26 27 SetRedirectURIs([]string) ClientBuilder 28 SetLogoURI(string) ClientBuilder 29 30 SetJWKSURI(string) ClientBuilder 31 SetJWKS([]byte) ClientBuilder 32 33 SetCertificateMetadata(certificateMetaddata string) ClientBuilder 34 SetTLSClientAuthSanDNS(tlsClientAuthSanDNS string) ClientBuilder 35 SetTLSClientAuthSanEmail(tlsClientAuthSanEmail string) ClientBuilder 36 SetTLSClientAuthSanIP(tlsClientAuthSanIP string) ClientBuilder 37 SetTLSClientAuthSanURI(tlsClientAuthSanURI string) ClientBuilder 38 SetExtraProperties(map[string]string) ClientBuilder 39 40 Build() (ClientMetadata, error) 41 } 42 43 type clientBuilder struct { 44 jwks []byte 45 jwksURI string 46 idpClientMetadata *clientMetadata 47 certificateMetadata string 48 tlsClientAuthSanDNS string 49 tlsClientAuthSanEmail string 50 tlsClientAuthSanIP string 51 tlsClientAuthSanURI string 52 } 53 54 // NewClientMetadataBuilder - create a new instance of builder to construct client metadata 55 func NewClientMetadataBuilder() ClientBuilder { 56 return &clientBuilder{ 57 idpClientMetadata: &clientMetadata{}, 58 } 59 } 60 61 func (b *clientBuilder) SetClientName(name string) ClientBuilder { 62 b.idpClientMetadata.ClientName = name 63 return b 64 } 65 66 func (b *clientBuilder) SetScopes(scopes []string) ClientBuilder { 67 b.idpClientMetadata.Scope = Scopes(scopes) 68 return b 69 } 70 71 func (b *clientBuilder) SetGrantTypes(grantTypes []string) ClientBuilder { 72 b.idpClientMetadata.GrantTypes = grantTypes 73 return b 74 } 75 76 func (b *clientBuilder) SetResponseType(responseTypes []string) ClientBuilder { 77 b.idpClientMetadata.ResponseTypes = responseTypes 78 return b 79 } 80 81 func (b *clientBuilder) SetTokenEndpointAuthMethod(tokenAuthMethod string) ClientBuilder { 82 b.idpClientMetadata.TokenEndpointAuthMethod = tokenAuthMethod 83 return b 84 } 85 86 func (b *clientBuilder) SetRedirectURIs(redirectURIs []string) ClientBuilder { 87 b.idpClientMetadata.RedirectURIs = redirectURIs 88 return b 89 } 90 91 func (b *clientBuilder) SetLogoURI(logoURI string) ClientBuilder { 92 b.idpClientMetadata.LogoURI = logoURI 93 return b 94 } 95 96 func (b *clientBuilder) SetJWKSURI(jwksURI string) ClientBuilder { 97 b.jwksURI = jwksURI 98 return b 99 } 100 101 func (b *clientBuilder) SetJWKS(jwks []byte) ClientBuilder { 102 b.jwks = jwks 103 return b 104 } 105 106 func (b *clientBuilder) SetCertificateMetadata(certificateMetadata string) ClientBuilder { 107 b.certificateMetadata = certificateMetadata 108 return b 109 } 110 111 func (b *clientBuilder) SetTLSClientAuthSanDNS(tlsClientAuthSanDNS string) ClientBuilder { 112 b.tlsClientAuthSanDNS = tlsClientAuthSanDNS 113 return b 114 } 115 116 func (b *clientBuilder) SetTLSClientAuthSanEmail(tlsClientAuthSanEmail string) ClientBuilder { 117 b.tlsClientAuthSanEmail = tlsClientAuthSanEmail 118 return b 119 } 120 121 func (b *clientBuilder) SetTLSClientAuthSanIP(tlsClientAuthSanIP string) ClientBuilder { 122 b.tlsClientAuthSanIP = tlsClientAuthSanIP 123 return b 124 } 125 126 func (b *clientBuilder) SetTLSClientAuthSanURI(tlsClientAuthSanURI string) ClientBuilder { 127 b.tlsClientAuthSanURI = tlsClientAuthSanURI 128 return b 129 } 130 131 func (b *clientBuilder) SetExtraProperties(extraProperties map[string]string) ClientBuilder { 132 b.idpClientMetadata.extraProperties = extraProperties 133 return b 134 } 135 136 func (b *clientBuilder) decodePublicKeyJWKS() (jwk.Key, error) { 137 p, err := util.ParsePublicKey(b.jwks) 138 if err != nil { 139 return nil, err 140 } 141 142 key, err := jwk.FromRaw(p) 143 if err != nil { 144 return nil, fmt.Errorf("failed to parse public key: %s", err) 145 } 146 kid, _ := util.ComputeKIDFromDER(b.jwks) 147 key.Set(jwk.KeyIDKey, kid) 148 key.Set(jwk.KeyUsageKey, jwk.ForSignature) 149 150 return key, nil 151 } 152 153 func (b *clientBuilder) decodeCertificateJWKS() (string, jwk.Key, error) { 154 pemBlock, _ := pem.Decode(b.jwks) 155 if pemBlock == nil { 156 return "", nil, fmt.Errorf("failed to decode certificate") 157 } 158 159 cert, err := x509.ParseCertificate(pemBlock.Bytes) 160 if err != nil { 161 return "", nil, fmt.Errorf("failed to parse certificate: %s", err) 162 } 163 164 subjectDN := cert.Subject.String() 165 key, err := jwk.FromRaw(cert.PublicKey) 166 if err != nil { 167 return "", nil, fmt.Errorf("failed to parse client certificate: %s", err) 168 } 169 170 c := &jwkcert.Chain{} 171 c.Add([]byte(base64.StdEncoding.EncodeToString(pemBlock.Bytes))) 172 key.Set(jwk.X509CertChainKey, c) 173 key.Set(jwk.KeyUsageKey, jwk.ForSignature) 174 175 return subjectDN, key, nil 176 } 177 178 func (b *clientBuilder) setClientMetadataJWKS(key jwk.Key) error { 179 jwksBuf, err := json.Marshal(key) 180 if err != nil { 181 return err 182 } 183 b.idpClientMetadata.Jwks = map[string]interface{}{ 184 "keys": []json.RawMessage{json.RawMessage(jwksBuf)}, 185 } 186 187 return nil 188 } 189 190 func (b *clientBuilder) setPrivateKeyJWTProperties() error { 191 if len(b.jwks) == 0 && len(b.jwksURI) == 0 { 192 return fmt.Errorf("public key is required for private_key_jwt token authentication method") 193 } 194 if len(b.jwks) != 0 { 195 key, err := b.decodePublicKeyJWKS() 196 if err != nil { 197 return err 198 } 199 b.setClientMetadataJWKS(key) 200 } 201 b.idpClientMetadata.JwksURI = b.jwksURI 202 return nil 203 } 204 205 func (b *clientBuilder) setTLSClientAuthProperties() error { 206 if len(b.jwks) == 0 && len(b.jwksURI) == 0 { 207 return fmt.Errorf("client certificate is required for tls_client_auth/self_signed_tls_client_auth token authentication method") 208 } 209 if len(b.jwks) != 0 { 210 subjectDN, jwks, err := b.decodeCertificateJWKS() 211 if err != nil { 212 return err 213 } 214 b.setClientMetadataJWKS(jwks) 215 216 switch b.certificateMetadata { 217 case TLSClientAuthSanDNS: 218 if b.tlsClientAuthSanDNS == "" { 219 return fmt.Errorf("no value provided for tls_client_auth_san_dns") 220 } 221 b.idpClientMetadata.TLSClientAuthSanDNS = b.tlsClientAuthSanDNS 222 case TLSClientAuthSanEmail: 223 if b.tlsClientAuthSanEmail == "" { 224 return fmt.Errorf("no value provided for tls_client_auth_san_email") 225 } 226 b.idpClientMetadata.TLSClientAuthSanEmail = b.tlsClientAuthSanEmail 227 case TLSClientAuthSanIP: 228 if b.tlsClientAuthSanIP == "" { 229 return fmt.Errorf("no value provided for tls_client_auth_san_ip") 230 } 231 b.idpClientMetadata.TLSClientAuthSanIP = b.tlsClientAuthSanIP 232 case TLSClientAuthSanURI: 233 if b.tlsClientAuthSanURI == "" { 234 return fmt.Errorf("no value provided for tls_client_auth_san_uri") 235 } 236 b.idpClientMetadata.TLSClientAuthSanURI = b.tlsClientAuthSanURI 237 default: 238 b.idpClientMetadata.TLSClientAuthSubjectDN = subjectDN 239 } 240 } 241 b.idpClientMetadata.JwksURI = b.jwksURI 242 return nil 243 } 244 245 func (b *clientBuilder) Build() (ClientMetadata, error) { 246 responseTypes := make(map[string]string) 247 for _, grantType := range b.idpClientMetadata.GrantTypes { 248 if _, ok := grantTypeWithRedirects[grantType]; ok && len(b.idpClientMetadata.RedirectURIs) == 0 { 249 return nil, fmt.Errorf("invalid client metadata redirect uri should be set for %s grant type", grantType) 250 } 251 switch grantType { 252 case GrantTypeAuthorizationCode: 253 responseTypes[AuthResponseCode] = AuthResponseCode 254 case GrantTypeImplicit: 255 responseTypes[AuthResponseToken] = AuthResponseToken 256 } 257 } 258 b.idpClientMetadata.ResponseTypes = make([]string, 0) 259 if len(responseTypes) > 0 { 260 for responseTypes := range responseTypes { 261 b.idpClientMetadata.ResponseTypes = append(b.idpClientMetadata.ResponseTypes, responseTypes) 262 } 263 } 264 265 switch b.idpClientMetadata.GetTokenEndpointAuthMethod() { 266 case config.PrivateKeyJWT: 267 err := b.setPrivateKeyJWTProperties() 268 if err != nil { 269 return nil, err 270 } 271 case config.TLSClientAuth: 272 fallthrough 273 case config.SelfSignedTLSClientAuth: 274 err := b.setTLSClientAuthProperties() 275 if err != nil { 276 return nil, err 277 } 278 } 279 return b.idpClientMetadata, nil 280 }