mirror of https://github.com/apache/nifi.git
NIFI-7924 Add fallback claims for identifying user to OIDC provider
This closes #4630 Signed-off-by: Joey Frazee <jfrazee@apache.org>
This commit is contained in:
parent
817f621d6f
commit
f330078fff
|
@ -169,6 +169,7 @@ public abstract class NiFiProperties {
|
|||
public static final String SECURITY_USER_OIDC_PREFERRED_JWSALGORITHM = "nifi.security.user.oidc.preferred.jwsalgorithm";
|
||||
public static final String SECURITY_USER_OIDC_ADDITIONAL_SCOPES = "nifi.security.user.oidc.additional.scopes";
|
||||
public static final String SECURITY_USER_OIDC_CLAIM_IDENTIFYING_USER = "nifi.security.user.oidc.claim.identifying.user";
|
||||
public static final String SECURITY_USER_OIDC_FALLBACK_CLAIMS_IDENTIFYING_USER = "nifi.security.user.oidc.fallback.claims.identifying.user";
|
||||
|
||||
// apache knox
|
||||
public static final String SECURITY_USER_KNOX_URL = "nifi.security.user.knox.url";
|
||||
|
@ -1011,6 +1012,21 @@ public abstract class NiFiProperties {
|
|||
return getProperty(SECURITY_USER_OIDC_CLAIM_IDENTIFYING_USER, "email").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of fallback claims to be used to identify a user when the configured claim is empty for a user
|
||||
*
|
||||
* @return The list of fallback claims to be used to identify the user
|
||||
*/
|
||||
public List<String> getOidcFallbackClaimsIdentifyingUser() {
|
||||
String rawProperty = getProperty(SECURITY_USER_OIDC_FALLBACK_CLAIMS_IDENTIFYING_USER, "").trim();
|
||||
if (StringUtils.isBlank(rawProperty)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
List<String> fallbackClaims = Arrays.asList(rawProperty.split(","));
|
||||
return fallbackClaims.stream().map(String::trim).filter(s->!s.isEmpty()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSendServerVersion() {
|
||||
return Boolean.parseBoolean(getProperty(WEB_SHOULD_SEND_SERVER_VERSION, DEFAULT_WEB_SHOULD_SEND_SERVER_VERSION));
|
||||
}
|
||||
|
|
|
@ -373,6 +373,7 @@ If this value is `none`, NiFi will attempt to validate unsecured/plain tokens. O
|
|||
JSON Web Key (JWK) provided through the jwks_uri in the metadata found at the discovery URL.
|
||||
|`nifi.security.user.oidc.additional.scopes` | Comma separated scopes that are sent to OpenId Connect Provider in addition to `openid` and `email`.
|
||||
|`nifi.security.user.oidc.claim.identifying.user` | Claim that identifies the user to be logged in; default is `email`. May need to be requested via the `nifi.security.user.oidc.additional.scopes` before usage.
|
||||
|`nifi.security.user.oidc.fallback.claims.identifying.user` | Comma separated possible fallback claims used to identify the user in case `nifi.security.user.oidc.claim.identifying.user` claim is not present for the login user.
|
||||
|==================================================================================================================================================
|
||||
|
||||
[[saml]]
|
||||
|
|
|
@ -164,6 +164,7 @@
|
|||
<nifi.security.user.oidc.preferred.jwsalgorithm />
|
||||
<nifi.security.user.oidc.additional.scopes />
|
||||
<nifi.security.user.oidc.claim.identifying.user />
|
||||
<nifi.security.user.oidc.fallback.claims.identifying.user />
|
||||
|
||||
<!-- nifi.properties: apache knox -->
|
||||
<nifi.security.user.knox.url />
|
||||
|
|
|
@ -178,6 +178,7 @@ nifi.security.user.oidc.client.secret=${nifi.security.user.oidc.client.secret}
|
|||
nifi.security.user.oidc.preferred.jwsalgorithm=${nifi.security.user.oidc.preferred.jwsalgorithm}
|
||||
nifi.security.user.oidc.additional.scopes=${nifi.security.user.oidc.additional.scopes}
|
||||
nifi.security.user.oidc.claim.identifying.user=${nifi.security.user.oidc.claim.identifying.user}
|
||||
nifi.security.user.oidc.fallback.claims.identifying.user=${nifi.security.user.oidc.fallback.claims.identifying.user}
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=${nifi.security.user.knox.url}
|
||||
|
|
|
@ -439,8 +439,16 @@ public class StandardOidcIdentityProvider implements OidcIdentityProvider {
|
|||
identity = claimsSet.getStringClaim(EMAIL_CLAIM);
|
||||
logger.info("The 'email' claim was present. Using that claim to avoid extra remote call");
|
||||
} else {
|
||||
identity = retrieveIdentityFromUserInfoEndpoint(oidcTokens);
|
||||
logger.info("Retrieved identity from UserInfo endpoint");
|
||||
final List<String> fallbackClaims = properties.getOidcFallbackClaimsIdentifyingUser();
|
||||
for (String fallbackClaim : fallbackClaims) {
|
||||
if (availableClaims.contains(fallbackClaim)) {
|
||||
identity = claimsSet.getStringClaim(fallbackClaim);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(identity)) {
|
||||
identity = retrieveIdentityFromUserInfoEndpoint(oidcTokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -411,10 +411,28 @@ class StandardOidcIdentityProviderGroovyTest extends GroovyTestCase {
|
|||
assert exp <= System.currentTimeMillis() + 10_000
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertOIDCTokenToLoginAuthenticationTokenShouldHandleNoEmailClaimHasFallbackClaims() {
|
||||
// Arrange
|
||||
StandardOidcIdentityProvider soip = buildIdentityProviderWithMockTokenValidator(["getOidcClaimIdentifyingUser": "email", "getOidcFallbackClaimsIdentifyingUser": ["upn"] ])
|
||||
String expectedUpn = "xxx@aaddomain";
|
||||
|
||||
OIDCTokenResponse mockResponse = mockOIDCTokenResponse(["email": null, "upn": expectedUpn])
|
||||
logger.info("OIDC Token Response with no email and upn: ${mockResponse.dump()}")
|
||||
|
||||
String loginToken = soip.convertOIDCTokenToLoginAuthenticationToken(mockResponse)
|
||||
logger.info("NiFi token create with upn: ${loginToken}")
|
||||
// Assert
|
||||
// Split JWT into components and decode Base64 to JSON
|
||||
def (String contents, String expiration) = loginToken.tokenize("\\[\\]")
|
||||
logger.info("Token contents: ${contents} | Expiration: ${expiration}")
|
||||
assert contents =~ "LoginAuthenticationToken for ${expectedUpn} issued by https://accounts\\.issuer\\.com expiring at"
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertOIDCTokenToLoginAuthNTokenShouldHandleBlankIdentityAndNoEmailClaim() {
|
||||
// Arrange
|
||||
StandardOidcIdentityProvider soip = buildIdentityProviderWithMockTokenValidator(["getOidcClaimIdentifyingUser": "non-existent-claim"])
|
||||
StandardOidcIdentityProvider soip = buildIdentityProviderWithMockTokenValidator(["getOidcClaimIdentifyingUser": "non-existent-claim", "getOidcFallbackClaimsIdentifyingUser": [] ])
|
||||
|
||||
OIDCTokenResponse mockResponse = mockOIDCTokenResponse(["email": null])
|
||||
logger.info("OIDC Token Response: ${mockResponse.dump()}")
|
||||
|
|
Loading…
Reference in New Issue