[ 
https://issues.apache.org/jira/browse/NIFI-8406?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Vijay Jammi resolved NIFI-8406.
-------------------------------
    Resolution: Duplicate

Duplicate of NIFI-8413

> Oidc Identity Provider should support assertions as client credentials for 
> authenticating against the token endpoint
> --------------------------------------------------------------------------------------------------------------------
>
>                 Key: NIFI-8406
>                 URL: https://issues.apache.org/jira/browse/NIFI-8406
>             Project: Apache NiFi
>          Issue Type: Improvement
>          Components: Core Framework, Security
>    Affects Versions: 1.11.4
>            Reporter: Vijay Jammi
>            Priority: Major
>              Labels: OIDC, Security, assertion
>
> The current oidc client authentication methods (client_secret_post, 
> client_secret_basic) require client credentials (client_secret) to be stored 
> as plain text on the client's filesystem, which could also be inadvertently 
> checked into source control system.
> Due to these and other security considerations, we should be able to use 
> assertions as client credentials for authenticating against the token 
> endpoint. 
> While using assertions an oidc client will include client_assertion and 
> client_assertion_type parameters instead of passing the client_secret for 
> authentication.
> Details on the OAuth 2.0 specifications for client authentication using jwt 
> and assertions can be found under
>  # [RFC 7523, Section 2.2 (Using JWTs for Client 
> Authentication)|https://tools.ietf.org/html/rfc7523#section-2.2] 
>  # [RFC 7521 (Using Assertions for Client 
> Authentication)|https://tools.ietf.org/html/rfc7521#section-4.2].
> Summary of the changes needed for assertion based client authentication.
>  * Generate a pair of private and public key which can be made available to 
> Nifi via a keystore on the filesystem. 
>  * Make the public key or cert available to the Authorization Server.     
> Alternatively to allow key rotations, we could configure a JWKS URL within 
> Nifi to allow the authorization server download the public key using the 
> keyId (kid).
>  * While building the token request against the token endpoint, need 
> StandardOidcIdentityProvider to provide a way to build a private_key_jwt 
> based client authentication in addition to the existing client_secret_basic, 
> client_secret_post. 
> {code:java}
> if 
> (ClientAuthenticationMethod.PRIVATE_KEY_JWT.equals(clientAuthenticationMethod)){
>     
>      clientAuthentication = new PrivateKeyJWT(clientId, tokenEndpoint, 
> jwsAlgorithm, privateKey, keyId, null);
> }else if 
> (ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientAuthenticationMethod))
>  { 
>      clientAuthentication = new ClientSecretPost(clientId, clientSecret);
> } else { 
>      clientAuthentication = new ClientSecretBasic(clientId, clientSecret);
> }{code}
>  * Encode and sign the JWT token with the private key, conforming to RFC 
> 7523, section 2.2 and pass the signed token within the client_assertion 
> request parameter along with the client_assertion_type. 
> {code:java}
> POST https://<auth-host>:<port>/.../token HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
> client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
> client_assertion=eyJraWQiOiJkMlY2LS1OUG....hTMfA&
> grant_type=authorization_code&
> code=9ba8d85b-...-c7a6fb6dae55
> {code}
>  * The Authorization Server will use the client's public key or cert to 
> verify the signature of the JWT and issues the token
>  
> Nifi Token Exchange Process
> When authentication within Nifi is enabled via OpenId Connect, a user is 
> re-directed to the configured authorization endpoint (authorization server) 
> via Nifi's oidc/request endpoint. The user upon successfully authenticating 
> with the authorization server is directed back to Nifi's (oidc/callback 
> endpoint) with a temporary authorization code. This authorization code is 
> then exchanged for an ID Token by the OidcService via the Oidc Identity 
> Provider (StandardOidcIdentityProvider - 
> exchangeAuthorizationCode(authorizationGrant)). The identity provider 
> requests this exchange by authenticating itself against the token endpoint of 
> the authorization server and presenting the authorization grant. The 
> authorization server authenticates the client, validates the authorization 
> grant and upon successful validation it issues an access token to Nifi.
> Currently, the exchangeAuthorizationCode(...) on StandardOidcIdentityProvider 
> provides two methods of Client Authentication (client_secret_basic, 
> client_secret_post) which are both based on the Authorization Server issuing 
> a set of client credentials (client_secret) which are presented to the 
> authorization server as client credentials during token exchange. 
> {noformat}
> public String exchangeAuthorizationCode(final AuthorizationGrant 
> authorizationGrant) throws IOException { 
> ...
> // 1 - Build the client authentication using the clientId and clientSecret 
> obtained during the registration of the client with the authorization server
> if 
> (oidcProviderMetadata.getTokenEndpointAuthMethods().contains(ClientAuthenticationMethod.CLIENT_SECRET_POST))
>  { 
> clientAuthentication = new ClientSecretPost(clientId, clientSecret); 
> } else {
>  clientAuthentication = new ClientSecretBasic(clientId, clientSecret); 
> }
> // 2 - Build the token endpoint request with the above client authentication 
> TokenRequest request = new TokenRequest(tokenEndpoint, clientAuthentication, 
> authorizationGrant); 
> HTTPRequest tokenHttpRequest = request.toHTTPRequest();
> ...
> // 3 - Submit the token request and Get the token response TokenResponse 
> response = OIDCTokenResponseParser.parse(tokenHttpRequest.send());
> // 4 - Upon Successful Response get the ID Token and the User Identity 
> if (response.indicatesSuccess()) { 
> final OIDCTokenResponse oidcTokenResponse = (OIDCTokenResponse) response; 
> final OIDCTokens oidcTokens = oidcTokenResponse.getOIDCTokens();  
> // validate the access token and parse the claims  
> final IDTokenClaimsSet claimsSet = tokenValidator.validate(oidcJwt, null);  
> // attempt to extract the configured claim to access the user's identity; 
> default is 'email' 
> String identity = 
> claimsSet.getStringClaim(properties.getOidcClaimIdentifyingUser()); ... 
> }
> // 5 - If User Identity could not extracted out of the IDToken, lookup the 
> identity against the UserInfo endpoint 
> if (StringUtils.isBlank(identity)) { 
> ... 
> final BearerAccessToken bearerAccessToken = 
> oidcTokens.getBearerAccessToken(); 
> ... 
> // 7 - Invoke the UserInfo endpoint to lookup user identity against the 
> UserInfo endpoint 
> identity = lookupIdentityInUserInfoModified(bearerAccessToken);  ...
> } 
> ... 
> // 8 - Convert into a Nifi jwt for retrieval later 
> final LoginAuthenticationToken loginToken = new 
> LoginAuthenticationToken(identity, identity, expiresIn, 
> claimsSet.getIssuer().getValue()); 
> return jwtService.generateSignedToken(loginToken);
> }{noformat}
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to