Author: [email protected]
Date: Wed Mar 14 12:26:01 2012
New Revision: 2144
Log:
[AMDATUAUTH-126] Fixed token provider to facilitate using a shared key in a
clustered setup.
Added:
trunk/amdatu-auth/config/src/main/resources/org.amdatu.auth.tokenprovider.cfg
Modified:
trunk/amdatu-auth/test-integration/base/pom.xml
trunk/amdatu-auth/test-integration/base/src/main/java/org/amdatu/auth/test/integration/base/AuthFixture.java
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/TokenProvider.java
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/osgi/Activator.java
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/service/TokenProviderImpl.java
Added:
trunk/amdatu-auth/config/src/main/resources/org.amdatu.auth.tokenprovider.cfg
==============================================================================
--- (empty file)
+++
trunk/amdatu-auth/config/src/main/resources/org.amdatu.auth.tokenprovider.cfg
Wed Mar 14 12:26:01 2012
@@ -0,0 +1,33 @@
+# Copyright (c) 2010, 2011 The Amdatu Foundation
+#
+# Licensed 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.verning permissions and limitations
+# under the License.
+
+# The secret key used by the AES encryption in the token provider to encrypt
and
+# decrypt the Amdatu token, which is stored in a cookie. Ensure that you always
+# define your own key here. For that reason, by default this key is empty and
+# the token provider will not start without a valid key entered here.
+# You can use online key generators (ie
http://www.andrewscompanies.com/tools/wep.asp)
+# to generate a random key.
+# The token provider uses AES-128 encryption. AES-192 and AES-256 are not
supported by
+# Java out of the box (you would need to install the JCE unlimited strength
jars in the
+# security folder). For AES-128, a 16 bytes key is required. Hence, this
secret key
+# must contain 16 characters. The key may be longer, the token provider in
that case
+# however will only use the first 16 characters of the key as being the key.
+#
+# In a single server setup, you may choose to let the token provider a random
key
+# for you. In that case, specify the value "[randomkey]" (without the quotes).
+#
+# By default this key is empty, such that the admin is forced to think about
the
+# policy to be used here.
+secretkey=
Modified: trunk/amdatu-auth/test-integration/base/pom.xml
==============================================================================
--- trunk/amdatu-auth/test-integration/base/pom.xml (original)
+++ trunk/amdatu-auth/test-integration/base/pom.xml Wed Mar 14 12:26:01 2012
@@ -34,6 +34,13 @@
<scope>provided</scope>
<type>bundle</type>
</dependency>
+ <dependency>
+ <groupId>org.amdatu.auth</groupId>
+ <artifactId>org.amdatu.auth.tokenprovider</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
</dependencies>
<!--
Modified:
trunk/amdatu-auth/test-integration/base/src/main/java/org/amdatu/auth/test/integration/base/AuthFixture.java
==============================================================================
---
trunk/amdatu-auth/test-integration/base/src/main/java/org/amdatu/auth/test/integration/base/AuthFixture.java
(original)
+++
trunk/amdatu-auth/test-integration/base/src/main/java/org/amdatu/auth/test/integration/base/AuthFixture.java
Wed Mar 14 12:26:01 2012
@@ -18,10 +18,12 @@
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
-import java.util.Properties;
-
import org.amdatu.auth.oauth.server.OAuthServerConfig;
+import org.amdatu.auth.tokenprovider.TokenProvider;
import org.amdatu.core.itest.base.TestContext;
+
+import java.util.Properties;
+
import org.ops4j.pax.exam.Option;
public class AuthFixture {
@@ -70,6 +72,7 @@
public void configureOAuthServer(TestContext testContext) throws Exception
{
testContext.updateConfig(OAuthServerConfig.PID, getOAuthServerCfg());
+ testContext.updateConfig(TokenProvider.PID, getTokenProviderCfg());
}
private Properties getOAuthServerCfg() {
@@ -84,6 +87,12 @@
return properties;
}
+
+ private Properties getTokenProviderCfg() {
+ Properties properties = new Properties();
+ properties.put("secretkey", "[randomkey]");
+ return properties;
+ }
public void configureFSConsumerRegistry(TestContext testContext) throws
Exception {
testContext.updateConfig("org.amdatu.auth.oauth.consumerregistry.fs",
getFSConsumerRegistryCfg());
Modified:
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/TokenProvider.java
==============================================================================
---
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/TokenProvider.java
(original)
+++
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/TokenProvider.java
Wed Mar 14 12:26:01 2012
@@ -43,7 +43,12 @@
*
* @author ivol
*/
-public interface TokenProvider {
+public interface TokenProvider {
+ /**
+ * The PID of the configuration of this service.
+ */
+ String PID = "org.amdatu.auth.tokenprovider";
+
/**
* Name of the cookie that stores an Amdatu token.
*/
Modified:
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/osgi/Activator.java
==============================================================================
---
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/osgi/Activator.java
(original)
+++
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/osgi/Activator.java
Wed Mar 14 12:26:01 2012
@@ -20,8 +20,10 @@
import org.amdatu.core.tenant.Tenant;
import org.amdatu.libraries.utilities.osgi.ServiceDependentActivator;
import org.amdatu.web.rest.jaxrs.JaxRsSpi;
+
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
/**
@@ -41,9 +43,10 @@
// Create and register the Token provider service component.
manager.add(
createAdapterService(Tenant.class, null)
- .setInterface(TokenProvider.class.getName(), null)
+ .setInterface(new String[]{ManagedService.class.getName(),
TokenProvider.class.getName()}, null)
.setImplementation(TokenProviderImpl.class)
-
.add(createServiceDependency().setService(LogService.class).setRequired(true)));
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createConfigurationDependency().setPid(TokenProvider.PID)));
// Create and register the REST API for the token provider service
component.
// TODO: This REST interface is disabled for now for security reasons.
Modified:
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/service/TokenProviderImpl.java
==============================================================================
---
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/service/TokenProviderImpl.java
(original)
+++
trunk/amdatu-auth/tokenprovider/src/main/java/org/amdatu/auth/tokenprovider/service/TokenProviderImpl.java
Wed Mar 14 12:26:01 2012
@@ -13,14 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.amdatu.auth.tokenprovider.service;
-
+package org.amdatu.auth.tokenprovider.service;
+
+import org.amdatu.auth.tokenprovider.InvalidTokenException;
+import org.amdatu.auth.tokenprovider.Token;
+import org.amdatu.auth.tokenprovider.TokenProvider;
+import org.amdatu.auth.tokenprovider.TokenProviderException;
+import org.amdatu.auth.tokenprovider.TokenStorageProvider;
+import org.amdatu.core.tenant.Tenant;
+
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Dictionary;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -31,15 +39,10 @@
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
-import org.amdatu.auth.tokenprovider.InvalidTokenException;
-import org.amdatu.auth.tokenprovider.Token;
-import org.amdatu.auth.tokenprovider.TokenProvider;
-import org.amdatu.auth.tokenprovider.TokenProviderException;
-import org.amdatu.auth.tokenprovider.TokenStorageProvider;
-import org.amdatu.core.tenant.Tenant;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
@@ -47,281 +50,326 @@
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.ServiceDependency;
import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
/**
* This class provides tokens and nonces.
*
* @author ivol
- */
-public class TokenProviderImpl implements TokenProvider {
-
- /**
- * Name of the authorization header when a token is passed in the
"Authorization" header of a HTTP request.
- */
- public static final String AUTHORIZATION_HEADER = "Amdatu";
-
- // Tenant unaware service dependencies
- private volatile LogService m_logService;
+ */
+public class TokenProviderImpl implements TokenProvider, ManagedService {
+
+ /**
+ * Name of the authorization header when a token is passed in the
"Authorization" header of a HTTP request.
+ */
+ public static final String AUTHORIZATION_HEADER = "Amdatu";
+
+ // Tenant unaware service dependencies
+ private volatile LogService m_logService;
private volatile Tenant m_tenant;
private volatile DependencyManager m_dependencyManager;
-
+
// Tenant aware service dependencies
- private volatile TokenStorageProvider m_tokenStore;
-
- // Encryption and decryption key and ciphers
- private static final String ENCRYPTION_METHOD = "AES";
- private static final int PRIVATE_KEY_SIZE = 128;
- private static final String DEFAULT_CHARSET = "UTF-8";
- private SecretKey m_secretKey = null;
- private String m_privateKey = null;
- private static Cipher ENCRYPT_CHIPHER;
- private static Cipher DECRYPT_CIPHER;
-
- /**
- * Initialize this service.
- *
- * @throws NoSuchAlgorithmException
- * @throws InvalidKeyException
- * @throws NoSuchPaddingException
- * @throws UnsupportedEncodingException
- */
- public void init(final Component component) throws
NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException,
+ private volatile TokenStorageProvider m_tokenStore;
+
+ // Encryption and decryption key and ciphers
+ private static final String ENCRYPTION_METHOD = "AES";
+ private static final int ENCRYPTION_METHOD_BYTES = 128/8; // We use
AES-128 (128 bits = 16 bytes)
+ private static final String DEFAULT_CHARSET = "UTF-8";
+ private static final String SECRET_KEY_PROPERTY = "secretkey";
+ private static final String RANDOM_KEY = "[randomkey]";
+
+ // The secret key
+ private SecretKey m_secretKey = null;
+ private String m_privateKey = null;
+ private Cipher m_encryptCipher;
+ private Cipher m_decryptCipher;
+
+ /**
+ * Initialize this service.
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ * @throws NoSuchPaddingException
+ * @throws UnsupportedEncodingException
+ */
+ public void init(final Component component) throws
NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchPaddingException,
UnsupportedEncodingException {
List<ServiceDependency> dependencies = new
ArrayList<ServiceDependency>();
-
+
// Define tenant aware service dependencies
dependencies.add(getTenantServiceDependency(TokenStorageProvider.class));
-
- if (m_secretKey == null) {
- KeyGenerator keyGen = KeyGenerator.getInstance(ENCRYPTION_METHOD);
- keyGen.init(PRIVATE_KEY_SIZE);
- m_secretKey = keyGen.generateKey();
- m_privateKey = new
Base64().encodeToString(m_secretKey.getEncoded());
- }
- if (ENCRYPT_CHIPHER == null) {
- ENCRYPT_CHIPHER = Cipher.getInstance(ENCRYPTION_METHOD);
- ENCRYPT_CHIPHER.init(Cipher.ENCRYPT_MODE, m_secretKey);
- }
- if (DECRYPT_CIPHER == null) {
- DECRYPT_CIPHER = Cipher.getInstance(ENCRYPTION_METHOD);
- DECRYPT_CIPHER.init(Cipher.DECRYPT_MODE, m_secretKey);
- }
-
- component.add(dependencies);
- }
+ component.add(dependencies);
+ }
private ServiceDependency getTenantServiceDependency(Class<?> clazz) {
- String tenantFilter = "(&(" + Tenant.TENANT_ID_SERVICEPROPERTY + "="
+ m_tenant.getId()
+ String tenantFilter = "(&(" + Tenant.TENANT_ID_SERVICEPROPERTY + "=" +
m_tenant.getId()
+ ")(" + Constants.OBJECTCLASS + "=" + clazz.getName() + "))";
return m_dependencyManager.createServiceDependency()
.setService(clazz, tenantFilter)
.setRequired(true)
.setInstanceBound(true);
}
-
- public void start() {
+
+ public void start() throws Exception {
+ if (m_encryptCipher == null) {
+ m_encryptCipher = Cipher.getInstance(ENCRYPTION_METHOD);
+ m_encryptCipher.init(Cipher.ENCRYPT_MODE, m_secretKey);
+ }
+ if (m_decryptCipher == null) {
+ m_decryptCipher = Cipher.getInstance(ENCRYPTION_METHOD);
+ m_decryptCipher.init(Cipher.DECRYPT_MODE, m_secretKey);
+ }
+
m_logService.log(LogService.LOG_INFO,
- "Service '" + getClass().getName() + "' started for tenant '" +
m_tenant.getId() + "'");
+ "Service '" + getClass().getName() + "' started for tenant '" +
m_tenant.getId() + "'");
+ }
+
+ public void stop() {
+ m_logService.log(LogService.LOG_INFO,
+ "Service '" + getClass().getName() + "' stopped for tenant '" +
m_tenant.getId() + "'");
+ }
+
+ @SuppressWarnings("rawtypes")
+ public synchronized void updated(Dictionary properties) throws
ConfigurationException {
+ Object key = properties.get(SECRET_KEY_PROPERTY);
+ if (key != null && RANDOM_KEY.equals(key.toString())) {
+ // The value [randomkey] is intended for a single server setup. In
this case we generate a
+ // random key.
+ try {
+ KeyGenerator keyGen =
KeyGenerator.getInstance(ENCRYPTION_METHOD);
+ keyGen.init(ENCRYPTION_METHOD_BYTES*8);
+ m_secretKey = keyGen.generateKey();
+ m_privateKey = new
Base64().encodeToString(m_secretKey.getEncoded());
+ }
+ catch (NoSuchAlgorithmException e) {
+ throw new ConfigurationException(SECRET_KEY_PROPERTY, "Could
not generate random key", e);
+ }
+ }
+ else if (key != null && !key.toString().trim().isEmpty() &&
key.toString().length() >= ENCRYPTION_METHOD_BYTES) {
+ byte[] bytes = new byte[ENCRYPTION_METHOD_BYTES];
+ byte[] keyBytes = key.toString().getBytes();
+ if (keyBytes.length == ENCRYPTION_METHOD_BYTES) {
+ bytes = keyBytes;
+ } else {
+ // Chop off first ENCRYPTION_METHOD_BYTES bytes
+ for (int i=0; i<ENCRYPTION_METHOD_BYTES; i++) {
+ bytes[i] = keyBytes[i];
+ }
+ }
+
+ m_secretKey = new SecretKeySpec(bytes, ENCRYPTION_METHOD);
+ m_privateKey = new
Base64().encodeToString(m_secretKey.getEncoded());
+ }
+ else {
+ throw new ConfigurationException(SECRET_KEY_PROPERTY, "An invalid
secret key has been entered "
+ + "in the configuration of '" + TokenProvider.PID + "'. The
secret key must either equal '[randomkey]' "
+ + "or contain at least 16 characters. The token provider
service cannot be started "
+ + "without a valid secret key.");
+ }
+ }
+
+ private String generateSignature(final SortedMap<String, String>
attributes) throws TokenProviderException {
+ String signvalue = m_privateKey;
+ if (attributes != null && attributes.size() > 0) {
+ try {
+ signvalue += attributesToString(attributes);
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new TokenProviderException(e);
+ }
+ }
+ String signature = DigestUtils.md5Hex(signvalue);
+ return signature;
+ }
+
+ private boolean verifySignature(final SortedMap<String, String>
attributes, final String signature)
+ throws TokenProviderException {
+ String verifySignature = generateSignature(attributes);
+ return signature.equals(verifySignature);
+ }
+
+ // Converts a map of attribute keys and values into a single String
representation, using
+ // URL encoding
+ public String attributesToString(final SortedMap<String, String>
attributes) throws UnsupportedEncodingException {
+ StringBuffer result = new StringBuffer();
+ if (attributes != null && attributes.size() > 0) {
+ for (String key : attributes.keySet()) {
+ String value = attributes.get(key);
+ String encKey = URLEncoder.encode(key, DEFAULT_CHARSET);
+ String encValue = URLEncoder.encode(value, DEFAULT_CHARSET);
+ if (result.length() > 0) {
+ result.append(' ');
+ }
+ result.append(encKey);
+ result.append('=');
+ result.append(encValue);
+ }
+ }
+ return result.toString();
+ }
+
+ // Converts a single String into a map of attribute keys and values using
URL decoding
+ public SortedMap<String, String> stringToAttributes(final String string)
throws UnsupportedEncodingException {
+ SortedMap<String, String> attributes = null;
+ if (string != null && !"".equals(string)) {
+ attributes = new TreeMap<String, String>();
+ String[] keyvalues = string.split(" "); // space is the attribute
separator
+ for (String keyvalue : keyvalues) {
+ String[] entry = keyvalue.split("=");
+ String key = entry[0];
+ String value = entry[1];
+ attributes.put(key, URLDecoder.decode(value, DEFAULT_CHARSET));
+ }
+ }
+ return attributes;
}
-
- private String generateSignature(final SortedMap<String, String>
attributes) throws TokenProviderException {
- String signvalue = m_privateKey;
- if (attributes != null && attributes.size() > 0) {
- try {
- signvalue += attributesToString(attributes);
- }
- catch (UnsupportedEncodingException e) {
- throw new TokenProviderException(e);
- }
- }
- String signature = DigestUtils.md5Hex(signvalue);
- return signature;
- }
-
- private boolean verifySignature(final SortedMap<String, String>
attributes, final String signature)
- throws TokenProviderException {
- String verifySignature = generateSignature(attributes);
- return signature.equals(verifySignature);
- }
-
- // Converts a map of attribute keys and values into a single String
representation, using
- // URL encoding
- public String attributesToString(final SortedMap<String, String>
attributes) throws UnsupportedEncodingException {
- StringBuffer result = new StringBuffer();
- if (attributes != null && attributes.size() > 0) {
- for (String key : attributes.keySet()) {
- String value = attributes.get(key);
- String encKey = URLEncoder.encode(key, DEFAULT_CHARSET);
- String encValue = URLEncoder.encode(value, DEFAULT_CHARSET);
- if (result.length() > 0) {
- result.append(' ');
- }
- result.append(encKey);
- result.append('=');
- result.append(encValue);
- }
- }
- return result.toString();
- }
-
- // Converts a single String into a map of attribute keys and values using
URL decoding
- public SortedMap<String, String> stringToAttributes(final String string)
throws UnsupportedEncodingException {
- SortedMap<String, String> attributes = null;
- if (string != null && !"".equals(string)) {
- attributes = new TreeMap<String, String>();
- String[] keyvalues = string.split(" "); // space is the attribute
separator
- for (String keyvalue : keyvalues) {
- String[] entry = keyvalue.split("=");
- String key = entry[0];
- String value = entry[1];
- attributes.put(key, URLDecoder.decode(value, DEFAULT_CHARSET));
- }
- }
- return attributes;
- }
-
- public String generateToken(final SortedMap<String, String> attributes)
throws TokenProviderException {
- try {
- if (attributes.containsKey(NONCE)) {
- throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + NONCE
- + "' is a preserved name");
- }
- if (attributes.containsKey(TIMESTAMP)) {
- throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + TIMESTAMP
- + "' is a preserved name");
- }
- if (attributes.containsKey(TENANTID)) {
- throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + TENANTID
- + "' is a preserved name");
- }
-
- // Add nonce and timestamp attributes
- String nonce = DigestUtils.md5Hex(new
Long(System.nanoTime()).toString());
- attributes.put(NONCE, nonce);
- String timestamp = new Long(System.currentTimeMillis()).toString();
- attributes.put(TIMESTAMP, timestamp);
- attributes.put(TENANTID, m_tenant.getId());
-
- // First create the unencrypted token
- String signature = generateSignature(attributes);
- String token = signature + " " + attributesToString(attributes);
-
- // Encode the token using UTF-8
- byte[] utf8 = token.getBytes(DEFAULT_CHARSET);
-
- // Encrypt it
- byte[] enc = ENCRYPT_CHIPHER.doFinal(utf8);
-
- // Encode to base64
+
+ public String generateToken(final SortedMap<String, String> attributes)
throws TokenProviderException {
+ try {
+ if (attributes.containsKey(NONCE)) {
+ throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + NONCE
+ + "' is a preserved name");
+ }
+ if (attributes.containsKey(TIMESTAMP)) {
+ throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + TIMESTAMP
+ + "' is a preserved name");
+ }
+ if (attributes.containsKey(TENANTID)) {
+ throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + TENANTID
+ + "' is a preserved name");
+ }
+
+ // Add nonce and timestamp attributes
+ String nonce = DigestUtils.md5Hex(new
Long(System.nanoTime()).toString());
+ attributes.put(NONCE, nonce);
+ String timestamp = new Long(System.currentTimeMillis()).toString();
+ attributes.put(TIMESTAMP, timestamp);
+ attributes.put(TENANTID, m_tenant.getId());
+
+ // First create the unencrypted token
+ String signature = generateSignature(attributes);
+ String token = signature + " " + attributesToString(attributes);
+
+ // Encode the token using UTF-8
+ byte[] utf8 = token.getBytes(DEFAULT_CHARSET);
+
+ // Encrypt it
+ byte[] enc = m_encryptCipher.doFinal(utf8);
+
+ // Encode to base64
String encryptedToken =
StringUtils.newStringUtf8(Base64.encodeBase64(enc, false));
-
+
// Store the encrypted token
// NB: our token secret is null, since there is no party with
which we can share the
- // token secret
- m_tokenStore.addToken(new Token(encryptedToken, null,
System.currentTimeMillis()));
-
- return encryptedToken;
- }
- catch (BadPaddingException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
- }
- catch (IllegalBlockSizeException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
- }
- catch (UnsupportedEncodingException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
- }
- return null;
- }
-
- public SortedMap<String, String> verifyToken(final String encryptedToken)
throws TokenProviderException,
- InvalidTokenException {
- try {
- // First verify that this token was generated by us
- if (!m_tokenStore.hasToken(encryptedToken)) {
- throw new InvalidTokenException("Token is invalid, token
unknown");
- }
-
- // Decode base64 to get bytes
- byte[] dec = Base64.decodeBase64(encryptedToken);
-
- // Decrypt
- byte[] utf8 = DECRYPT_CIPHER.doFinal(dec);
-
- // Decode using UTF-8
- String token = new String(utf8, DEFAULT_CHARSET);
-
- // Now this token consists of signature + token attributes
- String signature;
- SortedMap<String, String> attributes = null;
- if (token.indexOf(" ") != -1) {
- signature = token.substring(0, token.indexOf(" "));
- attributes =
stringToAttributes(token.substring(token.indexOf(" ") + 1));
- }
- else {
- signature = token;
- }
-
- // Now verify if this signature is valid
- if (!verifySignature(attributes, signature)) {
- throw new InvalidTokenException("Token is invalid, signature
mismatch");
- }
- return attributes;
- }
- catch (BadPaddingException e) {
- throw new TokenProviderException(e);
- }
- catch (IllegalBlockSizeException e) {
- throw new TokenProviderException(e);
- }
- catch (UnsupportedEncodingException e) {
- throw new TokenProviderException(e);
- }
- }
-
- public String updateToken(final String encryptedToken, final
SortedMap<String, String> newAttributes)
- throws TokenProviderException, InvalidTokenException {
- // First validate that the token is valid and retrieve the original
token attributes
- SortedMap<String, String> attributes = verifyToken(encryptedToken);
-
- // Now update the token attributes with the new ones
- if (newAttributes != null && newAttributes.size() > 0) {
- for (String key : newAttributes.keySet()) {
- String value = newAttributes.get(key);
- attributes.put(key, value);
- }
- }
-
- // Generate a new token
- return generateToken(attributes);
- }
-
+ // token secret
+ m_tokenStore.addToken(new Token(encryptedToken, null,
System.currentTimeMillis()));
+
+ return encryptedToken;
+ }
+ catch (BadPaddingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ catch (IllegalBlockSizeException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ catch (UnsupportedEncodingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ return null;
+ }
+
+ public SortedMap<String, String> verifyToken(final String encryptedToken)
throws TokenProviderException,
+ InvalidTokenException {
+ try {
+ // First verify that this token was generated by us
+ if (!m_tokenStore.hasToken(encryptedToken)) {
+ throw new InvalidTokenException("Token is invalid, token
unknown");
+ }
+
+ // Decode base64 to get bytes
+ byte[] dec = Base64.decodeBase64(encryptedToken);
+
+ // Decrypt
+ byte[] utf8 = m_decryptCipher.doFinal(dec);
+
+ // Decode using UTF-8
+ String token = new String(utf8, DEFAULT_CHARSET);
+
+ // Now this token consists of signature + token attributes
+ String signature;
+ SortedMap<String, String> attributes = null;
+ if (token.indexOf(" ") != -1) {
+ signature = token.substring(0, token.indexOf(" "));
+ attributes =
stringToAttributes(token.substring(token.indexOf(" ") + 1));
+ }
+ else {
+ signature = token;
+ }
+
+ // Now verify if this signature is valid
+ if (!verifySignature(attributes, signature)) {
+ throw new InvalidTokenException("Token is invalid, signature
mismatch");
+ }
+ return attributes;
+ }
+ catch (BadPaddingException e) {
+ throw new TokenProviderException(e);
+ }
+ catch (IllegalBlockSizeException e) {
+ throw new TokenProviderException(e);
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new TokenProviderException(e);
+ }
+ }
+
+ public String updateToken(final String encryptedToken, final
SortedMap<String, String> newAttributes)
+ throws TokenProviderException, InvalidTokenException {
+ // First validate that the token is valid and retrieve the original
token attributes
+ SortedMap<String, String> attributes = verifyToken(encryptedToken);
+
+ // Now update the token attributes with the new ones
+ if (newAttributes != null && newAttributes.size() > 0) {
+ for (String key : newAttributes.keySet()) {
+ String value = newAttributes.get(key);
+ attributes.put(key, value);
+ }
+ }
+
+ // Generate a new token
+ return generateToken(attributes);
+ }
+
public void invalidateToken(final String encryptedToken) {
- Token token = m_tokenStore.getToken(encryptedToken);
- m_tokenStore.removeToken(token);
- }
-
- public String getTokenFromRequest(final HttpServletRequest request) {
- // Use case 1: The token is send along in a cookie with the request.
The cookie is send
- // automatically when a request is send directly from the end users
browser to the Amdatu server.
- if (request.getCookies() != null) {
- for (Cookie cookie : request.getCookies()) {
- if (TokenProvider.TOKEN_COOKIE_NAME.equals(cookie.getName())) {
- return cookie.getValue();
- }
- }
- }
-
- // Use case 2: When requests are not send from a browser (for example
calls to gadgets.ui.makeRequest
- // proxied via an openSocial container) the token can be send in the
Authorization header (like Basic
- // and Digest HTTP authentication).
- String authHeader = request.getHeader("Authorization");
- if (authHeader != null && !authHeader.isEmpty()) {
- if (authHeader.startsWith(AUTHORIZATION_HEADER + " ")) {
- return authHeader.substring(authHeader.indexOf(" ") + 1);
- }
- }
- return null;
- }
-}
+ Token token = m_tokenStore.getToken(encryptedToken);
+ m_tokenStore.removeToken(token);
+ }
+
+ public String getTokenFromRequest(final HttpServletRequest request) {
+ // Use case 1: The token is send along in a cookie with the request.
The cookie is send
+ // automatically when a request is send directly from the end users
browser to the Amdatu server.
+ if (request.getCookies() != null) {
+ for (Cookie cookie : request.getCookies()) {
+ if (TokenProvider.TOKEN_COOKIE_NAME.equals(cookie.getName())) {
+ return cookie.getValue();
+ }
+ }
+ }
+
+ // Use case 2: When requests are not send from a browser (for example
calls to gadgets.ui.makeRequest
+ // proxied via an openSocial container) the token can be send in the
Authorization header (like Basic
+ // and Digest HTTP authentication).
+ String authHeader = request.getHeader("Authorization");
+ if (authHeader != null && !authHeader.isEmpty()) {
+ if (authHeader.startsWith(AUTHORIZATION_HEADER + " ")) {
+ return authHeader.substring(authHeader.indexOf(" ") + 1);
+ }
+ }
+ return null;
+ }
+
+}
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits