You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2018/08/22 11:50:14 UTC

[cxf] branch 3.1.x-fixes updated (a1e6e6d -> 44216c8)

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

coheigea pushed a change to branch 3.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git.


    from a1e6e6d  Recording .gitmergeinfo Changes
     new 6f244b9  Recording .gitmergeinfo Changes
     new 44216c8  CXF-7806 - Add option to create JWT access tokens without persisting them

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitmergeinfo                                      |   1 +
 .../cxf/rs/security/oauth2/common/AccessToken.java |  39 ++++---
 .../oauth2/provider/AbstractOAuthDataProvider.java | 123 ++++++++++++---------
 .../services/AbstractAccessTokenValidator.java     |  62 ++++++++---
 .../oauth2/services/TokenIntrospectionService.java |  47 ++++++--
 .../cxf/rs/security/oauth2/utils/OAuthUtils.java   |  96 ++++++++--------
 .../security/oidc/idp/IdTokenResponseFilter.java   |  23 ++--
 7 files changed, 242 insertions(+), 149 deletions(-)


[cxf] 02/02: CXF-7806 - Add option to create JWT access tokens without persisting them

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 44216c8e5d081cfea61874281cb7f73f9f8e5b23
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Wed Aug 22 12:49:51 2018 +0100

    CXF-7806 - Add option to create JWT access tokens without persisting them
---
 .../cxf/rs/security/oauth2/common/AccessToken.java |  39 ++++---
 .../oauth2/provider/AbstractOAuthDataProvider.java | 123 ++++++++++++---------
 .../services/AbstractAccessTokenValidator.java     |  62 ++++++++---
 .../oauth2/services/TokenIntrospectionService.java |  47 ++++++--
 .../cxf/rs/security/oauth2/utils/OAuthUtils.java   |  96 ++++++++--------
 .../security/oidc/idp/IdTokenResponseFilter.java   |  23 ++--
 6 files changed, 241 insertions(+), 149 deletions(-)

diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
index 39699d4..5bee11e 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
@@ -27,6 +27,7 @@ import javax.persistence.FetchType;
 import javax.persistence.Id;
 import javax.persistence.MapKeyColumn;
 import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
 
 /**
  * Base Access Token representation
@@ -35,33 +36,34 @@ import javax.persistence.MappedSuperclass;
 public abstract class AccessToken implements Serializable {
 
     private static final long serialVersionUID = -5750544301887053480L;
-    
+
     private String tokenKey;
     private String tokenType;
     private String refreshToken;
     private long expiresIn = -1;
     private long issuedAt = -1;
     private String issuer;
-    
-    
+    private String encodedToken;
+
+
     private Map<String, String> parameters = new LinkedHashMap<String, String>();
-    
+
     protected AccessToken() {
-        
+
     }
-    
+
     protected AccessToken(String tokenType, String tokenKey) {
         this.tokenType = tokenType;
         this.tokenKey = tokenKey;
     }
-    
+
     protected AccessToken(String tokenType, String tokenKey,
                           long expiresIn, long issuedAt) {
         this(tokenType, tokenKey);
         this.expiresIn = expiresIn;
         this.issuedAt = issuedAt;
     }
-    
+
     protected AccessToken(String tokenType, String tokenKey,
                           long expiresIn, long issuedAt,
                           String refreshToken,
@@ -78,11 +80,11 @@ public abstract class AccessToken implements Serializable {
     public String getTokenType() {
         return tokenType;
     }
-    
+
     public void setTokenType(String type) {
         this.tokenType = type;
     }
-    
+
     /**
      * Returns the token key
      * @return the key
@@ -91,7 +93,7 @@ public abstract class AccessToken implements Serializable {
     public String getTokenKey() {
         return tokenKey;
     }
-    
+
     public void setTokenKey(String key) {
         this.tokenKey = key;
     }
@@ -113,9 +115,9 @@ public abstract class AccessToken implements Serializable {
     public String getRefreshToken() {
         return refreshToken;
     }
-    
+
     /**
-     * Gets token parameters 
+     * Gets token parameters
      * @return
      */
     @ElementCollection(fetch = FetchType.EAGER)
@@ -143,7 +145,7 @@ public abstract class AccessToken implements Serializable {
     public void setIssuedAt(long issuedAt) {
         this.issuedAt = issuedAt;
     }
-    
+
     /**
      * Sets additional token parameters
      * @param parameters the token parameters
@@ -159,4 +161,13 @@ public abstract class AccessToken implements Serializable {
     public void setIssuer(String issuer) {
         this.issuer = issuer;
     }
+
+    @Transient
+    public String getEncodedToken() {
+        return encodedToken;
+    }
+
+    public void setEncodedToken(String encodedToken) {
+        this.encodedToken = encodedToken;
+    }
 }
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
index 209e574..a699912 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
@@ -54,15 +54,16 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     private List<String> requiredScopes;
     private List<String> invisibleToClientScopes;
     private boolean supportPreauthorizedTokens;
-    
+
     private boolean useJwtFormatForAccessTokens;
+    private boolean persistJwtEncoding = true;
     private OAuthJoseJwtProducer jwtAccessTokenProducer;
     private Map<String, String> jwtAccessTokenClaimMap;
     private ProviderAuthenticationStrategy authenticationStrategy;
 
     protected AbstractOAuthDataProvider() {
     }
-    
+
     @Override
     public ServerAccessToken createAccessToken(AccessTokenRegistration reg)
         throws OAuthServiceException {
@@ -73,13 +74,13 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
         return at;
     }
-    
+
     protected ServerAccessToken doCreateAccessToken(AccessTokenRegistration atReg) {
         ServerAccessToken at = createNewAccessToken(atReg.getClient(), atReg.getSubject());
         at.setAudiences(atReg.getAudiences());
         at.setGrantType(atReg.getGrantType());
         List<String> theScopes = atReg.getApprovedScope();
-        List<OAuthPermission> thePermissions = 
+        List<OAuthPermission> thePermissions =
             convertScopeToPermissions(atReg.getClient(), theScopes);
         at.setScopes(thePermissions);
         at.setSubject(atReg.getSubject());
@@ -100,19 +101,23 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         if (isUseJwtFormatForAccessTokens()) {
             JwtClaims claims = createJwtAccessToken(at);
             String jose = processJwtAccessToken(claims);
-            at.setTokenKey(jose);
+            if (isPersistJwtEncoding()) {
+                at.setTokenKey(jose);
+            } else {
+                at.setEncodedToken(jose);
+            }
         }
-        
+
         return at;
     }
-    
+
     protected JwtClaims createJwtAccessToken(ServerAccessToken at) {
         JwtClaims claims = new JwtClaims();
         claims.setTokenId(at.getTokenKey());
-        
+
         // 'client_id' or 'cid', default client_id
-        String clientIdClaimName = 
-            JwtTokenUtils.getClaimName(OAuthConstants.CLIENT_ID, OAuthConstants.CLIENT_ID, 
+        String clientIdClaimName =
+            JwtTokenUtils.getClaimName(OAuthConstants.CLIENT_ID, OAuthConstants.CLIENT_ID,
                                              getJwtAccessTokenClaimMap());
         claims.setClaim(clientIdClaimName, at.getClient().getClientId());
         claims.setIssuedAt(at.getIssuedAt());
@@ -124,10 +129,10 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             if (userSubject.getId() != null) {
                 claims.setSubject(userSubject.getId());
             }
-            
+
             // 'username' by default to be consistent with the token introspection response
             final String usernameProp = "username";
-            String usernameClaimName = 
+            String usernameClaimName =
                 JwtTokenUtils.getClaimName(usernameProp, usernameProp, getJwtAccessTokenClaimMap());
             claims.setClaim(usernameClaimName, userSubject.getLogin());
         }
@@ -135,7 +140,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             claims.setIssuer(at.getIssuer());
         }
         if (!at.getScopes().isEmpty()) {
-            claims.setClaim(OAuthConstants.SCOPE, 
+            claims.setClaim(OAuthConstants.SCOPE,
                             OAuthUtils.convertPermissionsToScopeList(at.getScopes()));
         }
         // OAuth2 resource indicators (resource server audience)
@@ -180,22 +185,22 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
         return claims;
     }
-    
+
     protected ServerAccessToken createNewAccessToken(Client client, UserSubject userSub) {
         return new BearerAccessToken(client, accessTokenLifetime);
     }
-    
+
     @Override
     public void removeAccessToken(ServerAccessToken token) throws OAuthServiceException {
         revokeAccessToken(token.getTokenKey());
     }
-    
+
     @Override
     public ServerAccessToken refreshAccessToken(Client client, String refreshTokenKey,
                                                 List<String> restrictedScopes) throws OAuthServiceException {
-        RefreshToken currentRefreshToken = recycleRefreshTokens 
+        RefreshToken currentRefreshToken = recycleRefreshTokens
             ? revokeRefreshToken(refreshTokenKey) : getRefreshToken(refreshTokenKey);
-        if (currentRefreshToken == null) { 
+        if (currentRefreshToken == null) {
             throw new OAuthServiceException(OAuthConstants.ACCESS_DENIED);
         }
         if (OAuthUtils.isExpired(currentRefreshToken.getIssuedAt(), currentRefreshToken.getExpiresIn())) {
@@ -207,7 +212,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         if (recycleRefreshTokens) {
             revokeAccessTokens(currentRefreshToken);
         }
-        
+
         ServerAccessToken at = doRefreshAccessToken(client, currentRefreshToken, restrictedScopes);
         saveAccessToken(at);
         if (recycleRefreshTokens) {
@@ -217,11 +222,11 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
         return at;
     }
-    
+
     @Override
     public void revokeToken(Client client, String tokenKey, String tokenTypeHint) throws OAuthServiceException {
         ServerAccessToken accessToken = null;
-        if (!OAuthConstants.REFRESH_TOKEN.equals(tokenTypeHint)) { 
+        if (!OAuthConstants.REFRESH_TOKEN.equals(tokenTypeHint)) {
             accessToken = revokeAccessToken(tokenKey);
         }
         if (accessToken != null) {
@@ -237,7 +242,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             if (rt == null) {
                 return;
             }
-            
+
             unlinkRefreshAccessToken(rt, accessToken.getTokenKey());
             if (rt.getAccessTokens().isEmpty()) {
                 revokeRefreshToken(rt.getTokenKey());
@@ -245,7 +250,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
                 saveRefreshToken(rt);
             }
         }
-        
+
     }
 
     protected void revokeAccessTokens(RefreshToken currentRefreshToken) {
@@ -266,8 +271,8 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
     }
 
-        
-    
+
+
     @Override
     public List<OAuthPermission> convertScopeToPermissions(Client client, List<String> requestedScopes) {
         checkRequestedScopes(client, requestedScopes);
@@ -281,9 +286,9 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             if (!list.isEmpty()) {
                 return list;
             }
-        } 
+        }
         throw new OAuthServiceException("Requested scopes can not be mapped");
-        
+
     }
 
     protected void checkRequestedScopes(Client client, List<String> requestedScopes) {
@@ -292,7 +297,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
     }
 
-    protected void convertSingleScopeToPermission(Client client, 
+    protected void convertSingleScopeToPermission(Client client,
                                                   String scope,
                                                   List<OAuthPermission> perms) {
         OAuthPermission permission = permissionMap.get(scope);
@@ -303,9 +308,9 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     }
 
     @Override
-    public ServerAccessToken getPreauthorizedToken(Client client, 
+    public ServerAccessToken getPreauthorizedToken(Client client,
                                                    List<String> requestedScopes,
-                                                   UserSubject sub, 
+                                                   UserSubject sub,
                                                    String grantType) throws OAuthServiceException {
         if (!isSupportPreauthorizedTokens()) {
             return null;
@@ -321,15 +326,15 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
                 break;
             }
         }
-        if (token != null 
+        if (token != null
             && OAuthUtils.isExpired(token.getIssuedAt(), token.getExpiresIn())) {
             revokeToken(client, token.getTokenKey(), OAuthConstants.ACCESS_TOKEN);
             token = null;
         }
         return token;
-        
+
     }
-    
+
     protected boolean isRefreshTokenSupported(List<String> theScopes) {
         return theScopes.contains(OAuthConstants.REFRESH_TOKEN_SCOPE);
     }
@@ -384,7 +389,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         rt.setClientCodeVerifier(at.getClientCodeVerifier());
         return rt;
     }
-    
+
     protected void linkAccessTokenToRefreshToken(RefreshToken rt, ServerAccessToken at) {
         if (!rt.getAccessTokens().contains(at.getTokenKey())) {
             rt.getAccessTokens().add(at.getTokenKey());
@@ -394,8 +399,8 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         at.setRefreshToken(rt.getTokenKey());
     }
 
-    protected ServerAccessToken doRefreshAccessToken(Client client, 
-                                                     RefreshToken oldRefreshToken, 
+    protected ServerAccessToken doRefreshAccessToken(Client client,
+                                                     RefreshToken oldRefreshToken,
                                                      List<String> restrictedScopes) {
         ServerAccessToken at = createNewAccessToken(client, oldRefreshToken.getSubject());
         at.setAudiences(oldRefreshToken.getAudiences() != null
@@ -421,12 +426,16 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         if (isUseJwtFormatForAccessTokens()) {
             JwtClaims claims = createJwtAccessToken(at);
             String jose = processJwtAccessToken(claims);
-            at.setTokenKey(jose);
+            if (isPersistJwtEncoding()) {
+                at.setTokenKey(jose);
+            } else {
+                at.setEncodedToken(jose);
+            }
         }
 
         return at;
     }
-    
+
     public void setAccessTokenLifetime(long accessTokenLifetime) {
         this.accessTokenLifetime = accessTokenLifetime;
     }
@@ -434,7 +443,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     public void setRefreshTokenLifetime(long refreshTokenLifetime) {
         this.refreshTokenLifetime = refreshTokenLifetime;
     }
-    
+
     public void setRecycleRefreshTokens(boolean recycleRefreshTokens) {
         this.recycleRefreshTokens = recycleRefreshTokens;
         this.refreshTokenLock = recycleRefreshTokens ? null : new Object();
@@ -454,10 +463,10 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             }
         }
     }
-    
+
     public void close() {
     }
-    
+
     public Map<String, OAuthPermission> getPermissionMap() {
         return permissionMap;
     }
@@ -465,7 +474,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     public void setPermissionMap(Map<String, OAuthPermission> permissionMap) {
         this.permissionMap = permissionMap;
     }
-    
+
     public void setSupportedScopes(Map<String, String> scopes) {
         for (Map.Entry<String, String> entry : scopes.entrySet()) {
             OAuthPermission permission = new OAuthPermission(entry.getKey(), entry.getValue());
@@ -483,7 +492,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             OAuthUtils.injectContextIntoOAuthProvider(messageContext, authenticationStrategy);
         }
     }
-    
+
     protected void removeClientTokens(Client c) {
         List<RefreshToken> refreshTokens = getRefreshTokens(c, null);
         if (refreshTokens != null) {
@@ -498,7 +507,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
             }
         }
     }
-    
+
     @Override
     public Client removeClient(String clientId) {
         Client c = doGetClient(clientId);
@@ -549,15 +558,15 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
         return at;
     }
-    protected RefreshToken revokeRefreshToken(String refreshTokenKey) { 
+    protected RefreshToken revokeRefreshToken(String refreshTokenKey) {
         RefreshToken refreshToken = getRefreshToken(refreshTokenKey);
         if (refreshToken != null) {
             doRevokeRefreshToken(refreshToken);
         }
         return refreshToken;
     }
-    
-    
+
+
     protected abstract void saveAccessToken(ServerAccessToken serverToken);
     protected abstract void saveRefreshToken(RefreshToken refreshToken);
     protected abstract void doRevokeAccessToken(ServerAccessToken accessToken);
@@ -600,8 +609,8 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         this.supportPreauthorizedTokens = supportPreauthorizedTokens;
     }
     protected static boolean isClientMatched(Client c, UserSubject resourceOwner) {
-        return resourceOwner == null 
-            || c.getResourceOwnerSubject() != null 
+        return resourceOwner == null
+            || c.getResourceOwnerSubject() != null
                 && c.getResourceOwnerSubject().getLogin().equals(resourceOwner.getLogin());
     }
     protected static boolean isTokenMatched(ServerAccessToken token, Client c, UserSubject sub) {
@@ -613,7 +622,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
         }
         return false;
     }
-    public void setClients(List<Client> clients) {    
+    public void setClients(List<Client> clients) {
         for (Client c : clients) {
             setClient(c);
         }
@@ -634,11 +643,11 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     public void setJwtAccessTokenProducer(OAuthJoseJwtProducer jwtAccessTokenProducer) {
         this.jwtAccessTokenProducer = jwtAccessTokenProducer;
     }
-    
+
     protected String processJwtAccessToken(JwtClaims jwtCliams) {
         // It will JWS-sign (default) and/or JWE-encrypt
-        OAuthJoseJwtProducer processor = 
-            getJwtAccessTokenProducer() == null ? new OAuthJoseJwtProducer() : getJwtAccessTokenProducer(); 
+        OAuthJoseJwtProducer processor =
+            getJwtAccessTokenProducer() == null ? new OAuthJoseJwtProducer() : getJwtAccessTokenProducer();
         return processor.processJwt(new JwtToken(jwtCliams));
     }
 
@@ -649,4 +658,12 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
     public void setJwtAccessTokenClaimMap(Map<String, String> jwtAccessTokenClaimMap) {
         this.jwtAccessTokenClaimMap = jwtAccessTokenClaimMap;
     }
+
+    public boolean isPersistJwtEncoding() {
+        return persistJwtEncoding;
+    }
+
+    public void setPersistJwtEncoding(boolean persistJwtEncoding) {
+        this.persistJwtEncoding = persistJwtEncoding;
+    }
 }
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractAccessTokenValidator.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractAccessTokenValidator.java
index 4d80d89..f8ab2ae 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractAccessTokenValidator.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractAccessTokenValidator.java
@@ -31,6 +31,9 @@ import org.apache.cxf.jaxrs.ext.MessageContext;
 import org.apache.cxf.jaxrs.ext.MessageContextImpl;
 import org.apache.cxf.jaxrs.utils.ExceptionUtils;
 import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.rs.security.jose.jwt.JoseJwtConsumer;
+import org.apache.cxf.rs.security.jose.jwt.JwtException;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
 import org.apache.cxf.rs.security.oauth2.common.AccessTokenValidation;
 import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
 import org.apache.cxf.rs.security.oauth2.provider.AccessTokenValidator;
@@ -41,41 +44,43 @@ import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
 import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
 
 public abstract class AbstractAccessTokenValidator {
-    
+
     private static final String DEFAULT_AUTH_SCHEME = OAuthConstants.BEARER_AUTHORIZATION_SCHEME;
-    
+
 
     protected Set<String> supportedSchemes = new HashSet<String>();
     protected String realm;
-    
+
     private MessageContext mc;
     private List<AccessTokenValidator> tokenHandlers = Collections.emptyList();
     private OAuthDataProvider dataProvider;
-    
+
     private int maxValidationDataCacheSize;
     private ConcurrentHashMap<String, AccessTokenValidation> accessTokenValidations =
         new ConcurrentHashMap<String, AccessTokenValidation>();
-    
+    private JoseJwtConsumer jwtTokenConsumer;
+    private boolean persistJwtEncoding = true;
+
     public void setTokenValidator(AccessTokenValidator validator) {
         setTokenValidators(Collections.singletonList(validator));
     }
-    
+
     public void setTokenValidators(List<AccessTokenValidator> validators) {
         tokenHandlers = validators;
         for (AccessTokenValidator handler : validators) {
             supportedSchemes.addAll(handler.getSupportedAuthorizationSchemes());
         }
     }
-    
+
     public void setDataProvider(OAuthDataProvider provider) {
         dataProvider = provider;
     }
-    
+
     @Context
     public void setMessageContext(MessageContext context) {
         this.mc = context;
     }
-    
+
     public MessageContext getMessageContext() {
         return mc != null ? mc : new MessageContextImpl(PhaseInterceptorChain.getCurrentMessage());
     }
@@ -88,9 +93,9 @@ public abstract class AbstractAccessTokenValidator {
                 return handler;
             }
         }
-        return null;        
+        return null;
     }
-    
+
     /**
      * Get the access token
      */
@@ -100,10 +105,10 @@ public abstract class AbstractAccessTokenValidator {
         if (dataProvider == null && tokenHandlers.isEmpty()) {
             throw ExceptionUtils.toInternalServerErrorException(null, null);
         }
-        
+
         if (maxValidationDataCacheSize > 0) {
             accessTokenV = accessTokenValidations.get(authSchemeData);
-        } 
+        }
         ServerAccessToken localAccessToken = null;
         if (accessTokenV == null) {
             // Get the registered handler capable of processing the token
@@ -111,7 +116,7 @@ public abstract class AbstractAccessTokenValidator {
             if (handler != null) {
                 try {
                     // Convert the HTTP Authorization scheme data into a token
-                    accessTokenV = handler.validateAccessToken(getMessageContext(), authScheme, authSchemeData, 
+                    accessTokenV = handler.validateAccessToken(getMessageContext(), authScheme, authSchemeData,
                                                                extraProps);
                 } catch (OAuthServiceException ex) {
                     AuthorizationUtils.throwAuthorizationFailure(Collections.singleton(authScheme), realm);
@@ -122,8 +127,16 @@ public abstract class AbstractAccessTokenValidator {
             // Default processing if no registered providers available
             if (accessTokenV == null && dataProvider != null && authScheme.equals(DEFAULT_AUTH_SCHEME)) {
                 try {
-                    localAccessToken = dataProvider.getAccessToken(authSchemeData);
-                } catch (OAuthServiceException ex) {
+                    String cacheKey = authSchemeData;
+                    if (!persistJwtEncoding) {
+                        JoseJwtConsumer theConsumer =
+                            jwtTokenConsumer == null ? new JoseJwtConsumer() : jwtTokenConsumer;
+                        JwtToken token = theConsumer.getJwtToken(authSchemeData);
+                        cacheKey = token.getClaims().getTokenId();
+                    }
+
+                    localAccessToken = dataProvider.getAccessToken(cacheKey);
+                } catch (JwtException | OAuthServiceException ex) {
                     // to be handled next
                 }
                 if (localAccessToken == null) {
@@ -168,5 +181,20 @@ public abstract class AbstractAccessTokenValidator {
         this.maxValidationDataCacheSize = maxValidationDataCacheSize;
     }
 
-    
+    public JoseJwtConsumer getJwtTokenConsumer() {
+        return jwtTokenConsumer;
+    }
+
+    public void setJwtTokenConsumer(JoseJwtConsumer jwtTokenConsumer) {
+        this.jwtTokenConsumer = jwtTokenConsumer;
+    }
+
+    public boolean isPersistJwtEncoding() {
+        return persistJwtEncoding;
+    }
+
+    public void setPersistJwtEncoding(boolean persistJwtEncoding) {
+        this.persistJwtEncoding = persistJwtEncoding;
+    }
+
 }
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenIntrospectionService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenIntrospectionService.java
index c21d43e..3fe5461 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenIntrospectionService.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenIntrospectionService.java
@@ -34,6 +34,9 @@ import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.jaxrs.ext.MessageContext;
 import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+import org.apache.cxf.rs.security.jose.jwt.JoseJwtConsumer;
+import org.apache.cxf.rs.security.jose.jwt.JwtException;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
 import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
 import org.apache.cxf.rs.security.oauth2.common.TokenIntrospection;
 import org.apache.cxf.rs.security.oauth2.common.UserSubject;
@@ -49,14 +52,27 @@ public class TokenIntrospectionService {
     private boolean reportExtraTokenProperties = true;
     private MessageContext mc;
     private OAuthDataProvider dataProvider;
+    private JoseJwtConsumer jwtTokenConsumer;
+    private boolean persistJwtEncoding = true;
+
     @POST
     @Produces({MediaType.APPLICATION_JSON })
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public TokenIntrospection getTokenIntrospection(@Encoded MultivaluedMap<String, String> params) {
         checkSecurityContext();
         String tokenId = params.getFirst(OAuthConstants.TOKEN_ID);
+        if (!persistJwtEncoding) {
+            try {
+                JoseJwtConsumer theConsumer = jwtTokenConsumer == null ? new JoseJwtConsumer() : jwtTokenConsumer;
+                JwtToken token = theConsumer.getJwtToken(tokenId);
+                tokenId = token.getClaims().getTokenId();
+            } catch (JwtException ex) {
+                return new TokenIntrospection(false);
+            }
+        }
+
         ServerAccessToken at = dataProvider.getAccessToken(tokenId);
-        if (at == null || OAuthUtils.isExpired(at.getIssuedAt(), at.getExpiresIn())) { 
+        if (at == null || OAuthUtils.isExpired(at.getIssuedAt(), at.getExpiresIn())) {
             return new TokenIntrospection(false);
         }
         TokenIntrospection response = new TokenIntrospection(true);
@@ -77,18 +93,18 @@ public class TokenIntrospectionService {
         if (at.getIssuer() != null) {
             response.setIss(at.getIssuer());
         }
-        
+
         response.setIat(at.getIssuedAt());
         if (at.getExpiresIn() > 0) {
             response.setExp(at.getIssuedAt() + at.getExpiresIn());
         }
-        
+
         response.setTokenType(at.getTokenType());
-        
+
         if (reportExtraTokenProperties) {
             response.getExtensions().putAll(at.getExtraProperties());
         }
-        
+
         return response;
     }
 
@@ -102,7 +118,7 @@ public class TokenIntrospectionService {
             LOG.warning("Authenticated Principal is not available");
             ExceptionUtils.toNotAuthorizedException(null, null);
         }
-        
+
     }
 
     public void setBlockUnsecureRequests(boolean blockUnsecureRequests) {
@@ -116,7 +132,7 @@ public class TokenIntrospectionService {
     public void setDataProvider(OAuthDataProvider dataProvider) {
         this.dataProvider = dataProvider;
     }
-    
+
     @Context
     public void setMessageContext(MessageContext context) {
         this.mc = context;
@@ -125,4 +141,21 @@ public class TokenIntrospectionService {
     public void setReportExtraTokenProperties(boolean reportExtraTokenProperties) {
         this.reportExtraTokenProperties = reportExtraTokenProperties;
     }
+
+    public JoseJwtConsumer getJwtTokenConsumer() {
+        return jwtTokenConsumer;
+    }
+
+    public void setJwtTokenConsumer(JoseJwtConsumer jwtTokenConsumer) {
+        this.jwtTokenConsumer = jwtTokenConsumer;
+    }
+
+    public boolean isPersistJwtEncoding() {
+        return persistJwtEncoding;
+    }
+
+    public void setPersistJwtEncoding(boolean persistJwtEncoding) {
+        this.persistJwtEncoding = persistJwtEncoding;
+    }
+
 }
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
index ffe0180..18412d1 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
@@ -68,7 +68,7 @@ import org.apache.cxf.security.SecurityContext;
 import org.apache.cxf.security.transport.TLSSessionInfo;
 
 /**
- * Various utility methods 
+ * Various utility methods
  */
 public final class OAuthUtils {
 
@@ -88,7 +88,7 @@ public final class OAuthUtils {
             throw new OAuthServiceException(ex);
         }
     }
-    
+
     public static boolean compareCertificateThumbprints(X509Certificate cert, String encodedThumbprint) {
         try {
             byte[] thumbprint = createCertificateThumbprint(cert);
@@ -98,7 +98,7 @@ public final class OAuthUtils {
             return false;
         }
     }
-    
+
 
     public static boolean compareTlsCertificates(TLSSessionInfo tlsInfo,
                                           List<String> base64EncodedCerts) {
@@ -120,24 +120,24 @@ public final class OAuthUtils {
         }
         return false;
     }
-    
+
     public static boolean isMutualTls(javax.ws.rs.core.SecurityContext sc, TLSSessionInfo tlsSessionInfo) {
         // Pure 2-way TLS authentication
-        return tlsSessionInfo != null 
+        return tlsSessionInfo != null
             && StringUtils.isEmpty(sc.getAuthenticationScheme())
             && getRootTLSCertificate(tlsSessionInfo) != null;
     }
-    
+
     public static String getSubjectDnFromTLSCertificates(X509Certificate cert) {
         X500Principal x509Principal = cert.getSubjectX500Principal();
         return x509Principal.getName();
     }
-    
+
     public static String getIssuerDnFromTLSCertificates(X509Certificate cert) {
         X500Principal x509Principal = cert.getIssuerX500Principal();
         return x509Principal.getName();
     }
-    
+
     public static X509Certificate getRootTLSCertificate(TLSSessionInfo tlsInfo) {
         Certificate[] clientCerts = tlsInfo.getPeerCertificates();
         if (clientCerts != null && clientCerts.length > 0) {
@@ -145,7 +145,7 @@ public final class OAuthUtils {
         }
         return null;
     }
-    
+
     public static void injectContextIntoOAuthProvider(MessageContext context, Object provider) {
         Method dataProviderContextMethod = null;
         try {
@@ -162,7 +162,7 @@ public final class OAuthUtils {
             }
         }
     }
-    
+
     public static String setSessionToken(MessageContext mc) {
         return setSessionToken(mc, 0);
     }
@@ -175,8 +175,8 @@ public final class OAuthUtils {
     public static String setSessionToken(MessageContext mc, String sessionToken, int maxInactiveInterval) {
         return setSessionToken(mc, sessionToken, null, 0);
     }
-    public static String setSessionToken(MessageContext mc, String sessionToken, 
-                                                String attribute, int maxInactiveInterval) {    
+    public static String setSessionToken(MessageContext mc, String sessionToken,
+                                                String attribute, int maxInactiveInterval) {
         HttpSession session = mc.getHttpServletRequest().getSession();
         if (maxInactiveInterval > 0) {
             session.setMaxInactiveInterval(maxInactiveInterval);
@@ -192,12 +192,12 @@ public final class OAuthUtils {
     public static String getSessionToken(MessageContext mc, String attribute) {
         return getSessionToken(mc, attribute, true);
     }
-    public static String getSessionToken(MessageContext mc, String attribute, boolean remove) {    
+    public static String getSessionToken(MessageContext mc, String attribute, boolean remove) {
         HttpSession session = mc.getHttpServletRequest().getSession();
-        String theAttribute = attribute == null ? OAuthConstants.SESSION_AUTHENTICITY_TOKEN : attribute;  
+        String theAttribute = attribute == null ? OAuthConstants.SESSION_AUTHENTICITY_TOKEN : attribute;
         String sessionToken = (String)session.getAttribute(theAttribute);
         if (sessionToken != null && remove) {
-            session.removeAttribute(theAttribute);    
+            session.removeAttribute(theAttribute);
         }
         return sessionToken;
     }
@@ -225,7 +225,7 @@ public final class OAuthUtils {
         }
         return subject;
     }
-    
+
     public static String convertPermissionsToScope(List<OAuthPermission> perms) {
         StringBuilder sb = new StringBuilder();
         for (OAuthPermission perm : perms) {
@@ -239,7 +239,7 @@ public final class OAuthUtils {
         }
         return sb.toString();
     }
-    
+
     public static List<String> convertPermissionsToScopeList(List<OAuthPermission> perms) {
         List<String> list = new LinkedList<String>();
         for (OAuthPermission perm : perms) {
@@ -247,9 +247,9 @@ public final class OAuthUtils {
         }
         return list;
     }
-    
-    public static boolean isGrantSupportedForClient(Client client, 
-                                                    boolean canSupportPublicClients, 
+
+    public static boolean isGrantSupportedForClient(Client client,
+                                                    boolean canSupportPublicClients,
                                                     String grantType) {
         if (grantType == null || !client.isConfidential() && !canSupportPublicClients) {
             return false;
@@ -257,13 +257,13 @@ public final class OAuthUtils {
         List<String> allowedGrants = client.getAllowedGrantTypes();
         return allowedGrants.isEmpty() || allowedGrants.contains(grantType);
     }
-    
+
     public static List<String> parseScope(String requestedScope) {
         List<String> list = new LinkedList<String>();
         if (requestedScope != null) {
             String[] scopeValues = requestedScope.split(" ");
             for (String scope : scopeValues) {
-                if (!StringUtils.isEmpty(scope)) {        
+                if (!StringUtils.isEmpty(scope)) {
                     list.add(scope);
                 }
             }
@@ -280,34 +280,34 @@ public final class OAuthUtils {
         }
         return StringUtils.toHexString(CryptoUtils.generateSecureRandomBytes(byteSize));
     }
-    
+
     public static long getIssuedAt() {
         return System.currentTimeMillis() / 1000L;
     }
-    
+
     public static boolean isExpired(Long issuedAt, Long lifetime) {
         // At some point -1 was used to indicate an unlimited lifetime
-        // with 0 being introduced instead at a later stage. 
-        // In theory there still could be a code around initializing the tokens with -1. 
+        // with 0 being introduced instead at a later stage.
+        // In theory there still could be a code around initializing the tokens with -1.
         // Treating -1 and 0 the same way is reasonable and it also makes it easier to
         // deal with the token introspection responses with no issuedAt time reported
         return lifetime == null
             || lifetime < -1
             || lifetime > 0L && issuedAt + lifetime < System.currentTimeMillis() / 1000L;
     }
-    
-    public static boolean validateAudience(String providedAudience, 
+
+    public static boolean validateAudience(String providedAudience,
                                            List<String> allowedAudiences) {
-        return providedAudience == null 
+        return providedAudience == null
             || validateAudiences(Collections.singletonList(providedAudience), allowedAudiences);
     }
-    public static boolean validateAudiences(List<String> providedAudiences, 
+    public static boolean validateAudiences(List<String> providedAudiences,
                                             List<String> allowedAudiences) {
-        return StringUtils.isEmpty(providedAudiences) 
+        return StringUtils.isEmpty(providedAudiences)
                && StringUtils.isEmpty(allowedAudiences)
                || allowedAudiences.containsAll(providedAudiences);
     }
-    
+
     public static boolean checkRequestURI(String servletPath, String uri) {
         boolean wildcard = uri.endsWith("*");
         String theURI = wildcard ? uri.substring(0, uri.length() - 1) : uri;
@@ -325,8 +325,8 @@ public final class OAuthUtils {
         }
         return false;
     }
-    
-    public static List<String> getRequestedScopes(Client client, 
+
+    public static List<String> getRequestedScopes(Client client,
                                                   String scopeParameter,
                                                   boolean useAllClientScopes,
                                                   boolean partialMatchScopeValidation) {
@@ -346,21 +346,21 @@ public final class OAuthUtils {
                 }
             }
         }
-        
+
         return requestScopes;
     }
-    
+
     public static boolean validateScopes(List<String> requestScopes, List<String> registeredScopes,
                                          boolean partialMatchScopeValidation) {
         if (!registeredScopes.isEmpty()) {
-            // if it is a strict validation then pre-registered scopes have to contains all 
+            // if it is a strict validation then pre-registered scopes have to contains all
             // the current request scopes
             if (!partialMatchScopeValidation) {
                 return registeredScopes.containsAll(requestScopes);
             } else {
                 for (String requestScope : requestScopes) {
                     boolean match = false;
-                    for (String registeredScope : registeredScopes) { 
+                    for (String registeredScope : registeredScopes) {
                         if (requestScope.startsWith(registeredScope)) {
                             match = true;
                             break;
@@ -376,15 +376,17 @@ public final class OAuthUtils {
     }
 
     public static ClientAccessToken toClientAccessToken(ServerAccessToken serverToken, boolean supportOptionalParams) {
+        String tokenKey =
+            serverToken.getEncodedToken() != null ? serverToken.getEncodedToken() : serverToken.getTokenKey();
         ClientAccessToken clientToken = new ClientAccessToken(serverToken.getTokenType(),
-                                                              serverToken.getTokenKey());
+                                                              tokenKey);
         clientToken.setRefreshToken(serverToken.getRefreshToken());
         if (supportOptionalParams) {
             clientToken.setExpiresIn(serverToken.getExpiresIn());
             List<OAuthPermission> perms = serverToken.getScopes();
             String scopeString = OAuthUtils.convertPermissionsToScope(perms);
             if (!StringUtils.isEmpty(scopeString)) {
-                clientToken.setApprovedScope(scopeString);    
+                clientToken.setApprovedScope(scopeString);
             }
             clientToken.setParameters(new HashMap<String, String>(serverToken.getParameters()));
         }
@@ -393,27 +395,27 @@ public final class OAuthUtils {
 
     public static JwsSignatureProvider getClientSecretSignatureProvider(String clientSecret) {
         Properties sigProps = JwsUtils.loadSignatureOutProperties(false);
-        return JwsUtils.getHmacSignatureProvider(clientSecret, 
+        return JwsUtils.getHmacSignatureProvider(clientSecret,
                                                  getClientSecretSignatureAlgorithm(sigProps));
     }
     public static JwsSignatureVerifier getClientSecretSignatureVerifier(String clientSecret) {
         Properties sigProps = JwsUtils.loadSignatureOutProperties(false);
-        return JwsUtils.getHmacSignatureVerifier(clientSecret, 
+        return JwsUtils.getHmacSignatureVerifier(clientSecret,
                                                  getClientSecretSignatureAlgorithm(sigProps));
     }
-    
+
     public static JweDecryptionProvider getClientSecretDecryptionProvider(String clientSecret) {
         Properties props = JweUtils.loadEncryptionInProperties(false);
         byte[] key = StringUtils.toBytesUTF8(clientSecret);
         return JweUtils.getDirectKeyJweDecryption(key, getClientSecretContentAlgorithm(props));
     }
-    
+
     public static JweEncryptionProvider getClientSecretEncryptionProvider(String clientSecret) {
         Properties props = JweUtils.loadEncryptionInProperties(false);
         byte[] key = StringUtils.toBytesUTF8(clientSecret);
         return JweUtils.getDirectKeyJweEncryption(key, getClientSecretContentAlgorithm(props));
     }
-    
+
     private static ContentAlgorithm getClientSecretContentAlgorithm(Properties props) {
         String ctAlgoProp = props.getProperty(OAuthConstants.CLIENT_SECRET_CONTENT_ENCRYPTION_ALGORITHM);
         if (ctAlgoProp == null) {
@@ -423,9 +425,9 @@ public final class OAuthUtils {
         ctAlgo = ctAlgo != null ? ctAlgo : ContentAlgorithm.A128GCM;
         return ctAlgo;
     }
-    
+
     public static SignatureAlgorithm getClientSecretSignatureAlgorithm(Properties sigProps) {
-        
+
         String clientSecretSigProp = sigProps.getProperty(OAuthConstants.CLIENT_SECRET_SIGNATURE_ALGORITHM);
         if (clientSecretSigProp == null) {
             String sigProp = sigProps.getProperty(JoseConstants.RSSEC_SIGNATURE_ALGORITHM);
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java
index f7ed11f..7fe1e89 100644
--- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java
@@ -59,13 +59,13 @@ public class IdTokenResponseFilter extends OAuthServerJoseJwtProducer implements
         String idToken = getProcessedIdToken(st);
         if (idToken != null) {
             ct.getParameters().put(OidcUtils.ID_TOKEN, idToken);
-        } 
-        
+        }
+
     }
     private String getProcessedIdToken(ServerAccessToken st) {
         if (idTokenProvider != null) {
-            IdToken idToken = 
-                idTokenProvider.getIdToken(st.getClient().getClientId(), st.getSubject(), 
+            IdToken idToken =
+                idTokenProvider.getIdToken(st.getClient().getClientId(), st.getSubject(),
                                            OAuthUtils.convertPermissionsToScopeList(st.getScopes()));
             setAtHashAndNonce(idToken, st);
             return processJwt(new JwtToken(idToken), st.getClient());
@@ -84,17 +84,17 @@ public class IdTokenResponseFilter extends OAuthServerJoseJwtProducer implements
             }
         }
         return null;
-        
+
     }
     private void setAtHashAndNonce(IdToken idToken, ServerAccessToken st) {
         String rType = st.getResponseType();
         boolean atHashRequired = idToken.getAccessTokenHash() == null
             && (rType == null || !rType.equals(OidcUtils.ID_TOKEN_RESPONSE_TYPE));
-        boolean cHashRequired = idToken.getAuthorizationCodeHash() == null 
-            && rType != null 
+        boolean cHashRequired = idToken.getAuthorizationCodeHash() == null
+            && rType != null
             && (rType.equals(OidcUtils.CODE_ID_TOKEN_AT_RESPONSE_TYPE)
                 || rType.equals(OidcUtils.CODE_ID_TOKEN_RESPONSE_TYPE));
-        
+
         Message m = JAXRSUtils.getCurrentMessage();
         if (atHashRequired || cHashRequired) {
             Properties props = JwsUtils.loadSignatureOutProperties(false);
@@ -106,7 +106,8 @@ public class IdTokenResponseFilter extends OAuthServerJoseJwtProducer implements
             }
             if (sigAlgo != SignatureAlgorithm.NONE) {
                 if (atHashRequired) {
-                    String atHash = OidcUtils.calculateAccessTokenHash(st.getTokenKey(), sigAlgo);
+                    String tokenKey = st.getEncodedToken() != null ? st.getEncodedToken() : st.getTokenKey();
+                    String atHash = OidcUtils.calculateAccessTokenHash(tokenKey, sigAlgo);
                     idToken.setAccessTokenHash(atHash);
                 }
                 if (cHashRequired) {
@@ -125,13 +126,13 @@ public class IdTokenResponseFilter extends OAuthServerJoseJwtProducer implements
                 }
             }
         }
-        
+
         if (m != null && m.getExchange().containsKey(OAuthConstants.NONCE)) {
             idToken.setNonce((String)m.getExchange().get(OAuthConstants.NONCE));
         } else if (st.getNonce() != null) {
             idToken.setNonce(st.getNonce());
         }
-        
+
     }
     public void setIdTokenProvider(IdTokenProvider idTokenProvider) {
         this.idTokenProvider = idTokenProvider;


[cxf] 01/02: Recording .gitmergeinfo Changes

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6f244b9713c8c08603cf1191183782cb4ca83002
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Wed Aug 22 12:49:37 2018 +0100

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index 23e911a..9ca011d 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -884,6 +884,7 @@ B e79f5cbb66d12d1db6e4c6154cfbb736e983f3c3
 B e7b178a92302786eca0233f9d176ded2d9086dde
 B e7e75c58c283d0178c6929cf298a68f41f6a8459
 B e824784db1bda81c68aaa407f471588acea38865
+B e850737cdc33373a00f40c57b728ac9b7a95d0be
 B e856de5370025ec6f897ef214e7f898fd8cb6756
 B e8d054818bc5d44d53fdd7fea377186d6264bf18
 B e90f3dd6422fa059ebea4c92763c73c8685e185e