You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by go...@apache.org on 2017/11/14 17:55:33 UTC

[cxf-fediz] 03/03: id_token exp should be computed at creation time

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

gonzalad pushed a commit to branch 1.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git

commit c0631b318a180fe86a3410f0445f5caf4189fd5c
Author: gonzalad <ad...@yahoo.fr>
AuthorDate: Tue Nov 14 18:39:41 2017 +0100

    id_token exp should be computed at creation time
    
    id_token expiry claim is now computed at id_token generation time.
    
    It was previously computed from SAML token expiry.
    Since SAML token is generated once per OIDC httpSession
    and can be reused for generating multiple id_token, it introduced
    some issues where the id_token is generated with an already expired claim.
    
    We now compute the exp claim as :
    
     * use timeToLive attribute of FedizSubjectCreator if it is strictly positive.
     * use maxInactiveInterval from httpSession if it is strictly positive.
     * otherwise use the default of 1 hour.
---
 .../fediz/service/oidc/FedizSubjectCreator.java    | 124 ++++++++++-----------
 1 file changed, 56 insertions(+), 68 deletions(-)

diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/FedizSubjectCreator.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/FedizSubjectCreator.java
index e8ad831..dae3a10 100644
--- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/FedizSubjectCreator.java
+++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/FedizSubjectCreator.java
@@ -26,6 +26,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import javax.servlet.http.HttpSession;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.UriBuilder;
 
@@ -51,21 +52,23 @@ import org.opensaml.saml.saml2.core.Issuer;
 
 
 public class FedizSubjectCreator implements SubjectCreator {
+
+    private static final long DEFAULT_TIME_TO_LIVE = 3600L;
     private static final String ROLES_SCOPE = "roles";
     private boolean stripPathFromIssuerUri;
     private String issuer;
-    private long defaultTimeToLive = 3600L;
     private Map<String, String> supportedClaims = Collections.emptyMap();
+    private long timeToLive;
 
     @Override
     public OidcUserSubject createUserSubject(MessageContext mc,
-                                         MultivaluedMap<String, String> params) throws OAuthServiceException {
+                                             MultivaluedMap<String, String> params) throws OAuthServiceException {
         Principal principal = mc.getSecurityContext().getUserPrincipal();
 
         if (!(principal instanceof FedizPrincipal)) {
             throw new OAuthServiceException("Unsupported Principal");
         }
-        FedizPrincipal fedizPrincipal = (FedizPrincipal)principal;
+        FedizPrincipal fedizPrincipal = (FedizPrincipal) principal;
 
         // In the future FedizPrincipal will likely have JWT claims already prepared,
         // with IdToken being initialized here from those claims
@@ -74,13 +77,8 @@ public class FedizSubjectCreator implements SubjectCreator {
 
         oidcSub.setId(fedizPrincipal.getName());
 
-        IdToken idToken = convertToIdToken(mc,
-                                           fedizPrincipal.getLoginToken(),
-                                           oidcSub.getLogin(),
-                                           oidcSub.getId(),
-                                           fedizPrincipal.getClaims(),
-                                           fedizPrincipal.getRoleClaims(),
-                                           params);
+        IdToken idToken = convertToIdToken(mc, fedizPrincipal.getLoginToken(), oidcSub.getLogin(), oidcSub.getId(),
+                fedizPrincipal.getClaims(), fedizPrincipal.getRoleClaims(), params);
         oidcSub.setIdToken(idToken);
         oidcSub.setRoles(fedizPrincipal.getRoleClaims());
         // UserInfo can be populated and set on OidcUserSubject too.
@@ -89,47 +87,26 @@ public class FedizSubjectCreator implements SubjectCreator {
         return oidcSub;
     }
 
-    private IdToken convertToIdToken(MessageContext mc,
-            Element samlToken,
-            String subjectName,
-            String subjectId,
-            ClaimCollection claims,
-            List<String> roles,
-            MultivaluedMap<String, String> params) {
+    private IdToken convertToIdToken(MessageContext mc, Element samlToken, String subjectName, String subjectId,
+                                     ClaimCollection claims, List<String> roles,
+                                     MultivaluedMap<String, String> params) {
         // The current SAML Assertion represents an authentication record.
         // It has to be translated into IdToken (JWT) so that it can be returned
         // to client applications participating in various OIDC flows.
 
         IdToken idToken = new IdToken();
 
-        //TODO: make the mapping between the subject name and IdToken claim configurable
+        // TODO: make the mapping between the subject name and IdToken claim configurable
         idToken.setPreferredUserName(subjectName);
         idToken.setSubject(subjectId);
 
         Assertion saml2Assertion = getSaml2Assertion(samlToken);
-        if (saml2Assertion != null) {
-            // issueInstant
-            DateTime issueInstant = saml2Assertion.getIssueInstant();
-            if (issueInstant != null) {
-                idToken.setIssuedAt(issueInstant.getMillis() / 1000);
-            }
-
-            // expiryTime
-            if (saml2Assertion.getConditions() != null) {
-                DateTime expires = saml2Assertion.getConditions().getNotOnOrAfter();
-                if (expires != null) {
-                    idToken.setExpiryTime(expires.getMillis() / 1000);
-                }
-            }
-
-            // authInstant
-            if (!saml2Assertion.getAuthnStatements().isEmpty()) {
-                DateTime authInstant =
-                saml2Assertion.getAuthnStatements().get(0).getAuthnInstant();
-                idToken.setAuthenticationTime(authInstant.getMillis() / 1000L);
-            }
+        // authInstant
+        if (saml2Assertion != null && !saml2Assertion.getAuthnStatements().isEmpty()) {
+            DateTime authInstant = saml2Assertion.getAuthnStatements().get(0).getAuthnInstant();
+            idToken.setAuthenticationTime(authInstant.getMillis() / 1000L);
         }
-        // Check if default issuer, issuedAt and expiryTime values have to be set
+        // Check if default issuer, issuedAt values have to be set
         if (issuer != null) {
             String realIssuer = null;
             if (issuer.startsWith("/")) {
@@ -156,23 +133,27 @@ public class FedizSubjectCreator implements SubjectCreator {
             }
         }
 
+        // Compute exp claim
         long currentTimeInSecs = System.currentTimeMillis() / 1000;
-        if (idToken.getIssuedAt() == null) {
-            idToken.setIssuedAt(currentTimeInSecs);
-        }
-        if (idToken.getExpiryTime() == null) {
-            idToken.setExpiryTime(currentTimeInSecs + defaultTimeToLive);
+        idToken.setIssuedAt(currentTimeInSecs);
+        HttpSession httpSession = mc.getHttpServletRequest().getSession(false);
+        if (timeToLive > 0) {
+            idToken.setExpiryTime(timeToLive);
+        } else if (httpSession != null && httpSession.getMaxInactiveInterval() > 0) {
+            idToken.setExpiryTime(currentTimeInSecs + httpSession.getMaxInactiveInterval());
+        } else {
+            idToken.setExpiryTime(currentTimeInSecs + DEFAULT_TIME_TO_LIVE);
         }
 
         List<String> requestedClaimsList = new ArrayList<String>();
-        //Derive claims from scope
+        // Derive claims from scope
         String requestedScope = params.getFirst(OAuthConstants.SCOPE);
         if (requestedScope != null && !requestedScope.isEmpty()) {
             String[] scopes = requestedScope.split(" ");
-            //TODO: Note that if the consent screen enabled then it is feasible
+            // TODO: Note that if the consent screen enabled then it is feasible
             // that the claims added in this code after mapping the scopes to claims
             // may need to be removed if the user disapproves the related scope
-            
+
             // standard scope to claims mapping:
             requestedClaimsList.addAll(OidcUtils.getScopeClaims(scopes));
             // custom scopes to claims mapping
@@ -193,16 +174,16 @@ public class FedizSubjectCreator implements SubjectCreator {
                     continue;
                 }
                 if (ClaimTypes.FIRSTNAME.equals(c.getClaimType())) {
-                    idToken.setGivenName((String)c.getValue());
-                    firstName = (String)c.getValue();
+                    idToken.setGivenName((String) c.getValue());
+                    firstName = (String) c.getValue();
                 } else if (ClaimTypes.LASTNAME.equals(c.getClaimType())) {
-                    idToken.setFamilyName((String)c.getValue());
-                    lastName = (String)c.getValue();
+                    idToken.setFamilyName((String) c.getValue());
+                    lastName = (String) c.getValue();
                 } else if (ClaimTypes.EMAILADDRESS.equals(c.getClaimType())) {
-                    idToken.setEmail((String)c.getValue());
+                    idToken.setEmail((String) c.getValue());
                 } else if (supportedClaims.containsKey(c.getClaimType().toString())
-                    && requestedClaimsList.contains(supportedClaims.get(c.getClaimType().toString()))) {
-                    idToken.setClaim(supportedClaims.get(c.getClaimType().toString()), (String)c.getValue());
+                        && requestedClaimsList.contains(supportedClaims.get(c.getClaimType().toString()))) {
+                    idToken.setClaim(supportedClaims.get(c.getClaimType().toString()), (String) c.getValue());
                 }
 
             }
@@ -211,29 +192,28 @@ public class FedizSubjectCreator implements SubjectCreator {
             }
         }
 
-        if (roles != null && !roles.isEmpty() 
-            && supportedClaims.containsKey(FedizConstants.DEFAULT_ROLE_URI.toString())) {
-            
+        if (roles != null && !roles.isEmpty()
+                && supportedClaims.containsKey(FedizConstants.DEFAULT_ROLE_URI.toString())) {
+
             String roleClaimName = supportedClaims.get(FedizConstants.DEFAULT_ROLE_URI.toString());
             if (requestedClaimsList.contains(roleClaimName)) {
                 idToken.setClaim(roleClaimName, roles);
-            }            
+            }
         }
 
         return idToken;
     }
 
-
     private List<String> getCustomScopeClaims(String[] scopes) {
         // For now the only custom scope (to claims) mapping Fediz supports is
         // roles where the scope name is expected to be 'roles' and the role name must be configured
         String roleClaimName = supportedClaims.get(FedizConstants.DEFAULT_ROLE_URI.toString());
         if (roleClaimName != null && Arrays.asList(scopes).contains(ROLES_SCOPE)) {
-            return Collections.singletonList(roleClaimName);    
+            return Collections.singletonList(roleClaimName);
         } else {
             return Collections.emptyList();
         }
-        
+
     }
 
     private Assertion getSaml2Assertion(Element samlToken) {
@@ -247,16 +227,10 @@ public class FedizSubjectCreator implements SubjectCreator {
 
     }
 
-
     public void setIdTokenIssuer(String idTokenIssuer) {
         this.issuer = idTokenIssuer;
     }
 
-
-    public void setIdTokenTimeToLive(long idTokenTimeToLive) {
-        this.defaultTimeToLive = idTokenTimeToLive;
-    }
-
     /**
      * Set a map of supported claims. The map is from a SAML ClaimType URI String to a claim value that is
      * sent in the claims parameter. So for example:
@@ -272,4 +246,18 @@ public class FedizSubjectCreator implements SubjectCreator {
         this.stripPathFromIssuerUri = stripPathFromIssuerUri;
     }
 
+    /**
+     * Time to live in seconds (used for id_token exp claim).
+     *
+     * If this value is set and strictly positive, then the generated
+     * id_token will use this value for the exp claim.
+     *
+     * Otherwise, it will use maxInactiveInterval of httpSession, and
+     * if this later is not strictly positive, it will be 1 hour by default.
+     *
+     * @param timeToLive time to live in seconds of the id_token
+     */
+    public void setTimeToLive(long timeToLive) {
+        this.timeToLive = timeToLive;
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@cxf.apache.org" <co...@cxf.apache.org>.