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

Reply via email to