Author: sergeyb
Date: Wed Jan 22 18:17:24 2014
New Revision: 1560456
URL: http://svn.apache.org/r1560456
Log:
[CXF-5513] Prototyping the utility code for supporting the encryption of bearer
tokens
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
(with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
(with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
(with props)
Removed:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Property.java
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OAuthAuthorizationData.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Permission.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ServerAccessToken.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/UserSubject.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/bearer/BearerAccessToken.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/refresh/RefreshToken.java
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/AccessToken.java
Wed Jan 22 18:17:24 2014
@@ -45,11 +45,19 @@ public abstract class AccessToken implem
protected AccessToken(String tokenType, String tokenKey,
long expiresIn, long issuedAt) {
- this.tokenType = tokenType;
- this.tokenKey = tokenKey;
+ this(tokenType, tokenKey);
this.expiresIn = expiresIn;
this.issuedAt = issuedAt;
}
+
+ protected AccessToken(String tokenType, String tokenKey,
+ long expiresIn, long issuedAt,
+ String refreshToken,
+ Map<String, String> parameters) {
+ this(tokenType, tokenKey, expiresIn, issuedAt);
+ this.refreshToken = refreshToken;
+ this.parameters = parameters;
+ }
/**
* Returns the token type such as bearer, mac, etc
@@ -59,6 +67,10 @@ public abstract class AccessToken implem
return tokenType;
}
+ public void setTokenType(String type) {
+ this.tokenType = type;
+ }
+
/**
* Returns the token key
* @return the key
@@ -66,6 +78,10 @@ public abstract class AccessToken implem
public String getTokenKey() {
return tokenKey;
}
+
+ public void setTokenKey(String key) {
+ this.tokenKey = key;
+ }
/**
* Sets the refresh token key the client can use to obtain a new
@@ -109,8 +125,6 @@ public abstract class AccessToken implem
return issuedAt;
}
- // Can be set at the server or at the moment
- // the token is deserialized on the client
public void setIssuedAt(long issuedAt) {
this.issuedAt = issuedAt;
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
Wed Jan 22 18:17:24 2014
@@ -19,8 +19,10 @@
package org.apache.cxf.rs.security.oauth2.common;
import java.io.Serializable;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* Represents a registered third-party Client application
@@ -45,7 +47,7 @@ public class Client implements Serializa
private List<String> registeredScopes = new LinkedList<String>();
private List<String> registeredAudiences = new LinkedList<String>();
- private List<Property> properties = new LinkedList<Property>();
+ private Map<String, String> properties = new HashMap<String, String>();
private UserSubject subject;
public Client(String clientId, String clientSecret, boolean
isConfidential) {
@@ -225,7 +227,7 @@ public class Client implements Serializa
* Get the list of additional client properties
* @return the list of properties
*/
- public List<Property> getProperties() {
+ public Map<String, String> getProperties() {
return properties;
}
@@ -233,7 +235,7 @@ public class Client implements Serializa
* Set the list of additional client properties
* @param properties the properties
*/
- public void setProperties(List<Property> properties) {
+ public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OAuthAuthorizationData.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OAuthAuthorizationData.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OAuthAuthorizationData.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OAuthAuthorizationData.java
Wed Jan 22 18:17:24 2014
@@ -19,8 +19,9 @@
package org.apache.cxf.rs.security.oauth2.common;
import java.io.Serializable;
-import java.util.LinkedList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
@@ -47,7 +48,7 @@ public class OAuthAuthorizationData impl
private String applicationWebUri;
private String applicationDescription;
private String applicationLogoUri;
- private List<Property> extraApplicationProperties = new
LinkedList<Property>();
+ private Map<String, String> extraApplicationProperties = new
HashMap<String, String>();
private List<? extends Permission> permissions;
private String audience;
@@ -237,11 +238,11 @@ public class OAuthAuthorizationData impl
return replyTo;
}
- public List<Property> getExtraApplicationProperties() {
+ public Map<String, String> getExtraApplicationProperties() {
return extraApplicationProperties;
}
- public void setExtraApplicationProperties(List<Property>
extraApplicationProperties) {
+ public void setExtraApplicationProperties(Map<String, String>
extraApplicationProperties) {
this.extraApplicationProperties = extraApplicationProperties;
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Permission.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Permission.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Permission.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Permission.java
Wed Jan 22 18:17:24 2014
@@ -73,10 +73,12 @@ public class Permission implements Seria
/**
* Indicates if this permission has been allocated by default or not.
- * Authorization View handlers may use this property in order to restrict
- * the list of scopes which may be refused to non-default scopes only.
- * For example, the read-only check-box controls can be used to represent
- * the default scopes
+ * Authorization View handlers may use this property to optimize the way
the user selects the
+ * scopes.
+ * For example, assume that read', 'add' and 'update' scopes are supported
and the
+ * 'read' scope is always allocated. This can be presented at the UI level
as follows:
+ * the read-only check-box control will represent a 'read' scope and a
user will be able to
+ * optionally select 'add' and/or 'update' scopes, in addition to the
default 'read' one.
* @param isDefault true if the permission has been allocated by default
*/
public void setDefault(boolean value) {
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ServerAccessToken.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ServerAccessToken.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ServerAccessToken.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ServerAccessToken.java
Wed Jan 22 18:17:24 2014
@@ -21,6 +21,8 @@ package org.apache.cxf.rs.security.oauth
import java.util.LinkedList;
import java.util.List;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
/**
@@ -50,6 +52,20 @@ public abstract class ServerAccessToken
super(tokenType, tokenKey, expiresIn, issuedAt);
this.client = client;
}
+
+ protected ServerAccessToken(ServerAccessToken token, String key) {
+ super(token.getTokenType(),
+ key,
+ token.getExpiresIn(),
+ token.getIssuedAt(),
+ token.getRefreshToken(),
+ token.getParameters());
+ this.client = token.getClient();
+ this.grantType = token.getGrantType();
+ this.scopes = token.getScopes();
+ this.audience = token.getAudience();
+ this.subject = token.getSubject();
+ }
/**
* Returns the Client associated with this token
@@ -59,15 +75,6 @@ public abstract class ServerAccessToken
return client;
}
- @Deprecated
- /**
- * Returns the number of seconds this token can be valid after it was
issued
- * @return the seconds
- */
- public long getLifetime() {
- return getExpiresIn();
- }
-
/**
* Returns a list of opaque permissions/scopes
* @return the scopes
@@ -128,4 +135,10 @@ public abstract class ServerAccessToken
this.audience = audience;
}
+ protected static ServerAccessToken validateTokenType(ServerAccessToken
token, String expectedType) {
+ if (!token.getTokenType().equals(expectedType)) {
+ throw new OAuthServiceException(OAuthConstants.SERVER_ERROR);
+ }
+ return token;
+ }
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/UserSubject.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/UserSubject.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/UserSubject.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/UserSubject.java
Wed Jan 22 18:17:24 2014
@@ -19,8 +19,10 @@
package org.apache.cxf.rs.security.oauth2.common;
import java.io.Serializable;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
@@ -36,7 +38,7 @@ public class UserSubject implements Seri
private String login;
private String id;
private List<String> roles = new LinkedList<String>();
- private List<Property> properties = new LinkedList<Property>();
+ private Map<String, String> properties = new HashMap<String, String>();
public UserSubject() {
@@ -100,7 +102,7 @@ public class UserSubject implements Seri
* Get the list of additional user subject properties
* @return the list of properties
*/
- public List<Property> getProperties() {
+ public Map<String, String> getProperties() {
return properties;
}
@@ -108,7 +110,7 @@ public class UserSubject implements Seri
* Set the list of additional user subject properties
* @param properties the properties
*/
- public void setProperties(List<Property> properties) {
+ public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
Wed Jan 22 18:17:24 2014
@@ -22,6 +22,7 @@ package org.apache.cxf.rs.security.oauth
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpSession;
@@ -39,7 +40,6 @@ import org.apache.cxf.common.util.String
import org.apache.cxf.rs.security.oauth2.common.Client;
import org.apache.cxf.rs.security.oauth2.common.OAuthAuthorizationData;
import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
-import org.apache.cxf.rs.security.oauth2.common.Property;
import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
import org.apache.cxf.rs.security.oauth2.common.UserSubject;
import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
@@ -194,9 +194,8 @@ public abstract class RedirectionBasedGr
secData.setApplicationDescription(client.getApplicationDescription());
secData.setApplicationLogoUri(client.getApplicationLogoUri());
secData.setAudience(params.getFirst(OAuthConstants.CLIENT_AUDIENCE));
- List<Property> extraProperties = client.getProperties();
- secData.setExtraApplicationProperties(extraProperties == null ?
Collections.<Property>emptyList()
- : Collections.unmodifiableList(extraProperties));
+ Map<String, String> extraProperties = client.getProperties();
+ secData.setExtraApplicationProperties(extraProperties);
String replyTo = getMessageContext().getUriInfo()
.getAbsolutePathBuilder().path("decision").build().toString();
secData.setReplyTo(replyTo);
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/bearer/BearerAccessToken.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/bearer/BearerAccessToken.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/bearer/BearerAccessToken.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/bearer/BearerAccessToken.java
Wed Jan 22 18:17:24 2014
@@ -43,4 +43,7 @@ public class BearerAccessToken extends S
long issuedAt) {
super(client, OAuthConstants.BEARER_TOKEN_TYPE, tokenKey, lifetime,
issuedAt);
}
+ public BearerAccessToken(ServerAccessToken token, String newKey) {
+ super(validateTokenType(token, OAuthConstants.BEARER_TOKEN_TYPE),
newKey);
+ }
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/refresh/RefreshToken.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/refresh/RefreshToken.java?rev=1560456&r1=1560455&r2=1560456&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/refresh/RefreshToken.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/refresh/RefreshToken.java
Wed Jan 22 18:17:24 2014
@@ -54,6 +54,13 @@ public class RefreshToken extends Server
issuedAt);
}
+ public RefreshToken(ServerAccessToken token,
+ String key,
+ List<String> accessTokens) {
+ super(validateTokenType(token, OAuthConstants.REFRESH_TOKEN_TYPE),
key);
+ this.accessTokens = accessTokens;
+ }
+
public List<String> getAccessTokens() {
return accessTokens;
}
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java?rev=1560456&view=auto
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
(added)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
Wed Jan 22 18:17:24 2014
@@ -0,0 +1,431 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.rs.security.oauth2.utils;
+
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
+import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider;
+import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken;
+
+
+/**
+ * Encryption helpers
+ */
+public final class EncryptionUtils {
+ private static final String SEP = "|";
+ private EncryptionUtils() {
+ }
+
+ public static String getEncodedSecretKey(SecretKey key) throws Exception {
+ try {
+ return Base64UrlUtility.encode(key.getEncoded());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static SecretKey getSecretKey() throws Exception {
+ return getSecretKey("AES");
+ }
+
+ public static SecretKey getSecretKey(String symEncAlgo) throws Exception {
+ KeyGenerator keyGen = KeyGenerator.getInstance(symEncAlgo);
+ return keyGen.generateKey();
+ }
+
+ public static SecretKey getSecretKey(SecretKeyProperties props) throws
Exception {
+ KeyGenerator keyGen = KeyGenerator.getInstance(props.getKeyAlgo());
+ AlgorithmParameterSpec algoSpec = props.getAlgoSpec();
+ SecureRandom random = props.getSecureRandom();
+ if (algoSpec != null) {
+ if (random != null) {
+ keyGen.init(algoSpec, random);
+ } else {
+ keyGen.init(algoSpec);
+ }
+ } else {
+ if (random != null) {
+ keyGen.init(props.getKeySize(), random);
+ } else {
+ keyGen.init(props.getKeySize());
+ }
+ }
+
+ return keyGen.generateKey();
+ }
+
+ public static String encryptTokenWithSecretKey(ServerAccessToken token,
+ SecretKey symmetricKey) {
+ return encryptTokenWithSecretKey(token, symmetricKey, null);
+ }
+
+ public static String encryptTokenWithSecretKey(ServerAccessToken token,
+ SecretKey symmetricKey,
+ SecretKeyProperties props) {
+ String tokenSequence = tokenizeServerToken(token);
+ return encryptSequence(tokenSequence, symmetricKey, props);
+ }
+
+ public static String encryptRefreshTokenWithSecretKey(RefreshToken token,
SecretKey symmetricKey) {
+ return encryptRefreshTokenWithSecretKey(token, symmetricKey, null);
+ }
+
+ public static String encryptRefreshTokenWithSecretKey(RefreshToken token,
+ SecretKey
symmetricKey,
+
SecretKeyProperties props) {
+ String tokenSequence = tokenizeRefreshToken(token);
+
+ return encryptSequence(tokenSequence, symmetricKey, props);
+ }
+
+ public static String decryptTokenSequence(String encodedToken,
+ String encodedSecretKey) {
+ return decryptTokenSequence(encodedToken, encodedSecretKey, "AES");
+ }
+
+ public static String decryptTokenSequence(String encodedToken,
+ String encodedSecretKey,
+ String algo) {
+ try {
+ SecretKey key = decodeSecretKey(encodedSecretKey, algo);
+ return decryptTokenSequence(encodedToken, key);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static String decryptTokenSequence(String encodedToken,
+ String encodedSecretKey,
+ SecretKeyProperties props) {
+ try {
+ SecretKey key = decodeSecretKey(encodedSecretKey,
props.getKeyAlgo());
+ return decryptTokenSequence(encodedToken, key, props);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static String decryptTokenSequence(String encodedToken,
+ SecretKey key) {
+ return decryptTokenSequence(encodedToken, key, null);
+ }
+
+ public static String decryptTokenSequence(String encodedToken,
+ SecretKey key,
+ SecretKeyProperties props) {
+ try {
+ byte[] encryptedBytes = decodeSequence(encodedToken);
+ byte[] bytes = processBytes(encryptedBytes, key, props,
Cipher.DECRYPT_MODE);
+ return new String(bytes, "UTF-8");
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static ServerAccessToken decryptToken(OAuthDataProvider provider,
+ String encodedToken,
+ String encodedSecretKey) {
+ return decryptToken(provider, encodedToken, encodedSecretKey, "AES");
+ }
+
+ public static ServerAccessToken decryptToken(OAuthDataProvider provider,
+ String encodedToken,
+ String encodedSecretKey,
+ String algo) {
+ SecretKey key = decodeSecretKey(encodedSecretKey, algo);
+ return decryptToken(provider, encodedToken, key);
+ }
+
+ public static ServerAccessToken decryptToken(OAuthDataProvider provider,
+ String encodedToken,
+ String encodedSecretKey,
+ SecretKeyProperties props) {
+ SecretKey key = decodeSecretKey(encodedSecretKey, props.getKeyAlgo());
+ return decryptToken(provider, encodedToken, key, props);
+ }
+
+ public static ServerAccessToken decryptToken(OAuthDataProvider provider,
+ String encodedToken,
+ SecretKey key) {
+ return decryptToken(provider, encodedToken, key, null);
+ }
+
+ public static ServerAccessToken decryptToken(OAuthDataProvider provider,
+ String encodedToken,
+ SecretKey key,
+ SecretKeyProperties props) {
+ try {
+ String decryptedSequence = decryptTokenSequence(encodedToken, key,
props);
+ return recreateToken(provider, encodedToken, decryptedSequence);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static RefreshToken decryptRefreshToken(OAuthDataProvider provider,
+ String encodedToken,
+ SecretKey key) {
+ return decryptRefreshToken(provider, encodedToken, key, null);
+ }
+
+ public static RefreshToken decryptRefreshToken(OAuthDataProvider provider,
+ String encodedToken,
+ SecretKey key,
+ SecretKeyProperties props) {
+ try {
+ String decryptedSequence = decryptTokenSequence(encodedToken, key,
props);
+ return recreateRefreshToken(provider, encodedToken,
decryptedSequence);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static String encryptSequence(String sequence, SecretKey
symmetricKey,
+ SecretKeyProperties keyProps) {
+ try {
+ byte[] bytes = processBytes(sequence.getBytes("UTF-8"),
+ symmetricKey,
+ keyProps,
+ Cipher.ENCRYPT_MODE);
+ return Base64UrlUtility.encode(bytes);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static byte[] processBytes(byte[] bytes, SecretKey symmetricKey,
+ SecretKeyProperties keyProps, int mode)
{
+ try {
+ Cipher c = Cipher.getInstance(symmetricKey.getAlgorithm());
+ if (keyProps == null || keyProps.getAlgoSpec() == null &&
keyProps.getSecureRandom() == null) {
+ c.init(mode, symmetricKey);
+ } else {
+ AlgorithmParameterSpec algoSpec = keyProps.getAlgoSpec();
+ SecureRandom random = keyProps.getSecureRandom();
+ if (algoSpec == null) {
+ c.init(mode, symmetricKey, random);
+ } else if (random == null) {
+ c.init(mode, symmetricKey, algoSpec);
+ } else {
+ c.init(mode, symmetricKey, algoSpec, random);
+ }
+ }
+ return c.doFinal(bytes);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static SecretKey decodeSecretKey(String encodedSecretKey, String
algo) {
+ try {
+ byte[] secretKeyBytes = decodeSequence(encodedSecretKey);
+ return new SecretKeySpec(secretKeyBytes, algo);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static byte[] decodeSequence(String encodedSecretKey) {
+ try {
+ return Base64UrlUtility.decode(encodedSecretKey);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static ServerAccessToken recreateToken(OAuthDataProvider provider,
+ String newTokenKey,
+ String decryptedSequence) {
+ return recreateToken(provider, newTokenKey,
decryptedSequence.split("\\" + SEP));
+ }
+
+ public static RefreshToken recreateRefreshToken(OAuthDataProvider provider,
+ String newTokenKey,
+ String decryptedSequence) {
+ String[] parts = decryptedSequence.split("\\" + SEP);
+ ServerAccessToken token = recreateToken(provider, newTokenKey, parts);
+ return new RefreshToken(token,
+ newTokenKey,
+ parseSimpleList(parts[parts.length - 1]));
+ }
+
+ public static ServerAccessToken recreateToken(OAuthDataProvider provider,
+ String newTokenKey,
+ String[] parts) {
+
+
+ @SuppressWarnings("serial")
+ final ServerAccessToken newToken = new
ServerAccessToken(provider.getClient(parts[4]),
+ parts[1],
+ newTokenKey
== null ? parts[0] : newTokenKey,
+
Long.valueOf(parts[2]),
+
Long.valueOf(parts[3])) {
+ };
+
+ newToken.setRefreshToken(getStringPart(parts[5]));
+ newToken.setGrantType(getStringPart(parts[6]));
+ newToken.setAudience(getStringPart(parts[7]));
+ newToken.setParameters(parseSimpleMap(parts[8]));
+
+ // Permissions
+ if (!parts[9].trim().isEmpty()) {
+ List<OAuthPermission> perms = new LinkedList<OAuthPermission>();
+ String[] allPermParts = parts[9].split("\\.");
+ for (int i = 0; i + 4 < allPermParts.length; i = i + 5) {
+ OAuthPermission perm = new OAuthPermission(allPermParts[i],
allPermParts[i + 1]);
+ perm.setDefault(Boolean.valueOf(allPermParts[i + 2]));
+ perm.setHttpVerbs(parseSimpleList(allPermParts[i + 3]));
+ perm.setUris(parseSimpleList(allPermParts[i + 4]));
+ perms.add(perm);
+ }
+ newToken.setScopes(perms);
+ }
+ //UserSubject:
+ if (!parts[10].trim().isEmpty()) {
+ String[] subjectParts = parts[10].split("\\.");
+ UserSubject subject = new UserSubject(subjectParts[0],
getStringPart(subjectParts[1]));
+ subject.setRoles(parseSimpleList(subjectParts[2]));
+ subject.setProperties(parseSimpleMap(subjectParts[3]));
+ newToken.setSubject(subject);
+ }
+
+
+ return newToken;
+ }
+
+ private static String getStringPart(String str) {
+ return "null".equals(str) ? null : str;
+ }
+
+ private static String prepareSimpleString(String str) {
+ return str.trim().isEmpty() ? "" : str.substring(1, str.length() - 1);
+ }
+
+ private static List<String> parseSimpleList(String listStr) {
+ String pureStringList = prepareSimpleString(listStr);
+ if (pureStringList.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return Arrays.asList(pureStringList.split(","));
+ }
+ }
+
+ private static Map<String, String> parseSimpleMap(String mapStr) {
+ Map<String, String> props = new HashMap<String, String>();
+ List<String> entries = parseSimpleList(mapStr);
+ for (String entry : entries) {
+ String[] pair = entry.split("=");
+ props.put(pair[0], pair[1]);
+ }
+ return props;
+ }
+ private static String tokenizeRefreshToken(RefreshToken token) {
+ String seq = tokenizeServerToken(token);
+ return seq + SEP + token.getAccessTokens().toString();
+ }
+ private static String tokenizeServerToken(ServerAccessToken token) {
+ StringBuilder state = new StringBuilder();
+ // 0: key
+ state.append(token.getTokenKey());
+ // 1: type
+ state.append(SEP);
+ state.append(token.getTokenType());
+ // 2: expiresIn
+ state.append(SEP);
+ state.append(token.getExpiresIn());
+ // 3: issuedAt
+ state.append(SEP);
+ state.append(token.getIssuedAt());
+ // 4: client id
+ state.append(SEP);
+ state.append(token.getClient().getClientId());
+ // 5: refresh token
+ state.append(SEP);
+ state.append(token.getRefreshToken());
+ // 6: grant type
+ state.append(SEP);
+ state.append(token.getGrantType());
+ // 7: audience
+ state.append(SEP);
+ state.append(token.getAudience());
+ // 8: other parameters
+ state.append(SEP);
+ // {key=value, key=value}
+ state.append(token.getParameters().toString());
+ // 9: permissions
+ state.append(SEP);
+ if (token.getScopes().isEmpty()) {
+ state.append(" ");
+ } else {
+ for (OAuthPermission p : token.getScopes()) {
+ // 9.1
+ state.append(p.getPermission());
+ state.append(".");
+ // 9.2
+ state.append(p.getDescription());
+ state.append(".");
+ // 9.3
+ state.append(p.isDefault());
+ state.append(".");
+ // 9.4
+ state.append(p.getHttpVerbs().toString());
+ state.append(".");
+ // 9.5
+ state.append(p.getUris().toString());
+ }
+ }
+ // 10: user subject
+ state.append(SEP);
+ if (token.getSubject() != null) {
+ // 10.1
+ state.append(token.getSubject().getLogin());
+ state.append(".");
+ // 10.2
+ state.append(token.getSubject().getId());
+ state.append(".");
+ // 10.3
+ state.append(token.getSubject().getRoles().toString());
+ state.append(".");
+ // 10.4
+ state.append(token.getSubject().getProperties().toString());
+ } else {
+ state.append(" ");
+ }
+
+ return state.toString();
+ }
+
+
+}
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java?rev=1560456&view=auto
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
(added)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
Wed Jan 22 18:17:24 2014
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.oauth2.utils;
+
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+public class SecretKeyProperties {
+ private String keyAlgo;
+ private int keySize;
+ private SecureRandom secureRandom;
+ private AlgorithmParameterSpec algoSpec;
+ public SecretKeyProperties() {
+ this("AES", 128);
+ }
+ public SecretKeyProperties(String keyAlgo) {
+ this(keyAlgo, 128);
+ }
+ public SecretKeyProperties(String keyAlgo, int keySize) {
+ this.keyAlgo = keyAlgo;
+ this.keySize = keySize;
+ }
+ public String getKeyAlgo() {
+ return keyAlgo;
+ }
+ public void setKeyAlgo(String keyAlgo) {
+ this.keyAlgo = keyAlgo;
+ }
+ public int getKeySize() {
+ return keySize;
+ }
+ public void setKeySize(int keySize) {
+ this.keySize = keySize;
+ }
+ public SecureRandom getSecureRandom() {
+ return secureRandom;
+ }
+ public void setSecureRandom(SecureRandom secureRandom) {
+ this.secureRandom = secureRandom;
+ }
+ public AlgorithmParameterSpec getAlgoSpec() {
+ return algoSpec;
+ }
+ public void setAlgoSpec(AlgorithmParameterSpec algoSpec) {
+ this.algoSpec = algoSpec;
+ }
+
+
+}
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java?rev=1560456&view=auto
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
(added)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
Wed Jan 22 18:17:24 2014
@@ -0,0 +1,207 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.oauth2.utils;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.rs.security.oauth2.common.AccessTokenRegistration;
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
+import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.tokens.bearer.BearerAccessToken;
+import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class EncryptionUtilsTest extends Assert {
+
+ private CustomProvider p;
+
+ @Before
+ public void setUp() throws Exception {
+ p = new CustomProvider();
+ }
+
+ @After
+ public void tearDown() {
+ p = null;
+ }
+
+ @Test
+ public void testEncryptDecryptToken() throws Exception {
+ AccessTokenRegistration atr = prepareTokenRegistration();
+
+ // encrypt
+ ServerAccessToken token = p.createAccessToken(atr);
+ // decrypt
+ ServerAccessToken token2 = p.getAccessToken(token.getTokenKey());
+
+ // compare tokens
+ compareAccessTokens(token, token2);
+ }
+
+ private void compareAccessTokens(ServerAccessToken token,
ServerAccessToken token2) {
+ assertEquals(token.getTokenKey(), token2.getTokenKey());
+ assertEquals(token.getTokenType(), token2.getTokenType());
+ assertEquals(token.getIssuedAt(), token2.getIssuedAt());
+ assertEquals(token.getExpiresIn(), token2.getExpiresIn());
+ Client regClient1 = token.getClient();
+ Client regClient2 = token2.getClient();
+ assertEquals(regClient1.getClientId(), regClient2.getClientId());
+
+ UserSubject endUser1 = token.getSubject();
+ UserSubject endUser2 = token2.getSubject();
+ assertEquals(endUser1.getLogin(), endUser2.getLogin());
+ assertEquals(endUser1.getId(), endUser2.getId());
+ assertEquals(endUser1.getRoles(), endUser2.getRoles());
+
+ assertEquals(token.getRefreshToken(), token2.getRefreshToken());
+ assertEquals(token.getAudience(), token2.getAudience());
+ assertEquals(token.getGrantType(), token2.getGrantType());
+ assertEquals(token.getParameters(), token2.getParameters());
+
+ List<OAuthPermission> permissions = token.getScopes();
+ List<OAuthPermission> permissions2 = token2.getScopes();
+ assertEquals(1, permissions.size());
+ assertEquals(1, permissions2.size());
+ OAuthPermission perm1 = permissions.get(0);
+ OAuthPermission perm2 = permissions2.get(0);
+ assertEquals(perm1.getPermission(), perm2.getPermission());
+ assertEquals(perm1.getDescription(), perm2.getDescription());
+
+ RefreshToken refreshToken =
+ EncryptionUtils.decryptRefreshToken(p, token2.getRefreshToken(),
p.tokenKey);
+ assertEquals(1200L, refreshToken.getExpiresIn());
+ }
+
+ private AccessTokenRegistration prepareTokenRegistration() {
+ AccessTokenRegistration atr = new AccessTokenRegistration();
+ Client regClient = p.getClient("1");
+ atr.setClient(regClient);
+ atr.setGrantType("code");
+ atr.setAudience("http://localhost");
+ UserSubject endUser = new UserSubject("Barry", "BarryId");
+ atr.setSubject(endUser);
+ endUser.setRoles(Collections.singletonList("role1"));
+ return atr;
+ }
+
+ private class CustomProvider implements OAuthDataProvider {
+
+ private Map<String, Client> clients;
+ private SecretKey tokenKey;
+
+ private Set<String> tokens = new HashSet<String>();
+ private Map<String, String> refreshTokens = new HashMap<String,
String>();
+
+ public CustomProvider() throws Exception {
+ tokenKey = EncryptionUtils.getSecretKey();
+ clients = Collections.singletonMap("1", new Client("1", "2",
true));
+ }
+
+ @Override
+ public Client getClient(String clientId) throws OAuthServiceException {
+ return clients.get(clientId);
+ }
+
+ @Override
+ public ServerAccessToken createAccessToken(AccessTokenRegistration
accessTokenReg)
+ throws OAuthServiceException {
+
+ ServerAccessToken token = createNewToken(accessTokenReg);
+
+ String encryptedToken =
+ EncryptionUtils.encryptTokenWithSecretKey(token, tokenKey);
+
+ tokens.add(encryptedToken);
+ refreshTokens.put(token.getRefreshToken(), encryptedToken);
+ token.setTokenKey(encryptedToken);
+ return token;
+ }
+
+ @Override
+ public ServerAccessToken getAccessToken(String accessTokenKey) throws
OAuthServiceException {
+ return EncryptionUtils.decryptToken(this, accessTokenKey,
tokenKey);
+ }
+
+ @Override
+ public ServerAccessToken refreshAccessToken(Client client, String
refreshToken,
+ List<String>
requestedScopes)
+ throws OAuthServiceException {
+ return null;
+ }
+
+ @Override
+ public void removeAccessToken(ServerAccessToken accessToken) throws
OAuthServiceException {
+ tokens.remove(accessToken.getTokenKey());
+ }
+
+ @Override
+ public void revokeToken(Client client, String token, String
tokenTypeHint)
+ throws OAuthServiceException {
+ // complete
+ }
+
+ @Override
+ public ServerAccessToken getPreauthorizedToken(Client client,
List<String> requestedScopes,
+ UserSubject subject,
String grantType)
+ throws OAuthServiceException {
+ return null;
+ }
+
+ @Override
+ public List<OAuthPermission> convertScopeToPermissions(Client client,
List<String> requestedScope) {
+ return null;
+ }
+
+ private ServerAccessToken createNewToken(AccessTokenRegistration
accessTokenReg) {
+ ServerAccessToken token = new
BearerAccessToken(accessTokenReg.getClient(), 3600L);
+ token.setSubject(accessTokenReg.getSubject());
+
+ RefreshToken refreshToken = new
RefreshToken(accessTokenReg.getClient(),
+ "refresh",
+ 1200L,
+
OAuthUtils.getIssuedAt());
+
+ String encryptedRefreshToken =
EncryptionUtils.encryptTokenWithSecretKey(refreshToken, tokenKey);
+ token.setRefreshToken(encryptedRefreshToken);
+
+ token.setGrantType(accessTokenReg.getGrantType());
+ token.setAudience(accessTokenReg.getAudience());
+ token.setParameters(Collections.singletonMap("param", "value"));
+ token.setScopes(Collections.singletonList(
+ new OAuthPermission("read", "read permission")));
+ return token;
+ }
+
+ }
+}
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date