This is an automated email from the ASF dual-hosted git repository.

jfrazee pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new f330078  NIFI-7924 Add fallback claims for identifying user to OIDC 
provider
f330078 is described below

commit f330078fffd39feeb2b289f7e9de5113f9c78bb4
Author: sjyang18 <[email protected]>
AuthorDate: Tue Oct 13 02:49:26 2020 +0000

    NIFI-7924 Add fallback claims for identifying user to OIDC provider
    
    This closes #4630
    
    Signed-off-by: Joey Frazee <[email protected]>
---
 .../java/org/apache/nifi/util/NiFiProperties.java    | 16 ++++++++++++++++
 .../src/main/asciidoc/administration-guide.adoc      |  1 +
 .../nifi-framework/nifi-resources/pom.xml            |  1 +
 .../src/main/resources/conf/nifi.properties          |  1 +
 .../security/oidc/StandardOidcIdentityProvider.java  | 12 ++++++++++--
 .../StandardOidcIdentityProviderGroovyTest.groovy    | 20 +++++++++++++++++++-
 6 files changed, 48 insertions(+), 3 deletions(-)

diff --git 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index 6164a2e..af48f02 100644
--- 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -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));
     }
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc 
b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 08da126..d1856c9 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -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]]
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
index 2013d87..6b6faec 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
@@ -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 />
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
index be45e4a..a84bff9 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
@@ -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}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/oidc/StandardOidcIdentityProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/oidc/StandardOidcIdentityProvider.java
index a26926e..b69679c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/oidc/StandardOidcIdentityProvider.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/oidc/StandardOidcIdentityProvider.java
@@ -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);
+                }
             }
         }
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/oidc/StandardOidcIdentityProviderGroovyTest.groovy
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/oidc/StandardOidcIdentityProviderGroovyTest.groovy
index b42881a..c52d4cd 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/oidc/StandardOidcIdentityProviderGroovyTest.groovy
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/oidc/StandardOidcIdentityProviderGroovyTest.groovy
@@ -412,9 +412,27 @@ class StandardOidcIdentityProviderGroovyTest extends 
GroovyTestCase {
     }
 
     @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()}")

Reply via email to