[
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)