Adding validation token generator got login

Project: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/archiva-redback-core/commit/de5816ad
Tree: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/tree/de5816ad
Diff: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/diff/de5816ad

Branch: refs/heads/master
Commit: de5816adf044d94245bb9e97249b2d27e6507bce
Parents: e9bc481
Author: Martin Stockhammer <[email protected]>
Authored: Sat Feb 11 20:20:24 2017 +0100
Committer: Martin Stockhammer <[email protected]>
Committed: Sun Feb 12 14:02:01 2017 +0100

----------------------------------------------------------------------
 .../EncryptionFailedException.java              |  47 ++++
 .../authentication/InvalidTokenException.java   |  48 ++++
 .../redback/authentication/SimpleTokenData.java |  88 +++++++
 .../redback/authentication/TokenData.java       |  66 +++++
 .../redback/authentication/TokenManager.java    | 248 +++++++++++++++++++
 .../main/resources/META-INF/spring-context.xml  |   4 +-
 .../authentication/TokenManagerTest.java        | 153 ++++++++++++
 .../archiva/redback/rest/api/model/User.java    |  16 ++
 .../rest/services/DefaultLoginService.java      |  12 +
 .../redback/system/DefaultSecuritySystem.java   |  15 ++
 .../archiva/redback/system/SecuritySystem.java  |   8 +
 11 files changed, 704 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/EncryptionFailedException.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/EncryptionFailedException.java
 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/EncryptionFailedException.java
new file mode 100644
index 0000000..83c1079
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/EncryptionFailedException.java
@@ -0,0 +1,47 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Exception used by the token manager.
+ *
+ * Created by Martin Stockhammer on 11.02.17.
+ */
+public class EncryptionFailedException extends Exception {
+
+    private static final long serialVersionUID = -2275802156651048276L;
+
+    public EncryptionFailedException() {
+        super();
+    }
+
+    public EncryptionFailedException(String message) {
+        super(message);
+    }
+
+    public EncryptionFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public EncryptionFailedException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/InvalidTokenException.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/InvalidTokenException.java
 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/InvalidTokenException.java
new file mode 100644
index 0000000..b3af182
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/InvalidTokenException.java
@@ -0,0 +1,48 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+/**
+ * Exception used by the token manager.
+ *
+ * Created by Martin Stockhammer on 11.02.17.
+ */
+public class InvalidTokenException extends Exception {
+
+    private static final long serialVersionUID = -1148088610607667870L;
+
+    public InvalidTokenException() {
+        super();
+    }
+
+    public InvalidTokenException(String message) {
+        super(message);
+    }
+
+    public InvalidTokenException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public InvalidTokenException(Throwable cause) {
+        super(cause);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/SimpleTokenData.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/SimpleTokenData.java
 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/SimpleTokenData.java
new file mode 100644
index 0000000..e3302bf
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/SimpleTokenData.java
@@ -0,0 +1,88 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * Simple Token information class that contains a username and a lifetime.
+ *
+ * The class is not able to detect time manipulations. It is assumed that the
+ * current time of the system is correct.
+ *
+ * This class is immutable.
+ *
+ * Created by Martin Stockhammer on 03.02.17.
+ */
+public final class SimpleTokenData implements Serializable, TokenData {
+
+
+    private static final long serialVersionUID = 5907745449771921813L;
+
+    private final String user;
+    private final Date created;
+    private final Date validBefore;
+    private final long nonce;
+
+
+    /**
+     * Creates a new token info instance for the given user.
+     * The lifetime in milliseconds defines the invalidation date by
+     * adding the lifetime to the current time of instantiation.
+     *
+     * @param user The user name
+     * @param lifetime The number of milliseconds after that the token is 
invalid
+     * @param nonce Should be a random number and different for each instance.
+     */
+    public SimpleTokenData(final String user, final long lifetime, final long 
nonce) {
+        this.user=user;
+        this.created=new Date();
+        this.validBefore =new Date(created.getTime()+lifetime);
+        this.nonce = nonce;
+    }
+
+    @Override
+    public final String getUser() {
+        return user;
+    }
+
+    @Override
+    public final Date created() {
+        return created;
+    }
+
+    @Override
+    public final Date validBefore() {
+        return validBefore;
+    }
+
+    @Override
+    public final long getNonce()  {
+        return nonce;
+    }
+
+    @Override
+    public boolean isValid() {
+        return (new Date().getTime())<validBefore.getTime();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenData.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenData.java
 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenData.java
new file mode 100644
index 0000000..f641f3a
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenData.java
@@ -0,0 +1,66 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+import java.util.Date;
+
+/**
+ *
+ * This contains the token payload that is used for verification of tokens.
+ *
+ * Created by Martin Stockhammer on 11.02.17.
+ */
+public interface TokenData {
+
+    /**
+     * Returns the user name.
+     *
+     * @return The username property.
+     */
+    String getUser();
+
+    /**
+     * The date the token was created.
+     *
+     * @return The creation date.
+     */
+    Date created();
+
+    /**
+     * The date after that the token is invalid.
+     *
+     * @return The invalidation date.
+     */
+    Date validBefore();
+
+    /**
+     * The nonce that is stored in the token.
+     *
+     * @return The nonce.
+     */
+    long getNonce();
+
+    /**
+     * Returns true, if the token is valid.
+     *
+     * @return True, if valid, otherwise false.
+     */
+    boolean isValid();
+}

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenManager.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenManager.java
 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenManager.java
new file mode 100644
index 0000000..08538bd
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/main/java/org/apache/archiva/redback/authentication/TokenManager.java
@@ -0,0 +1,248 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+
+/**
+ *
+ * Class that manages tokens that are encrypted with a dynamic key. The tokens
+ * are converted into BASE64 strings.
+ *
+ * Each token contains information about username,
+ *
+ * Created by Martin Stockhammer on 03.02.17.
+ */
+@Service("tokenManager#jce")
+public class TokenManager {
+
+    private static final SecureRandom rd = new SecureRandom();
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private String algorithm = "AES/ECB/PKCS5Padding";
+    private int keySize = -1;
+    private Cipher deCipher;
+    private Cipher enCipher;
+
+    boolean paddingUsed = true;
+
+
+    @PostConstruct
+    public void initialize() throws NoSuchAlgorithmException, 
NoSuchPaddingException, InvalidKeyException, EncryptionFailedException, 
InvalidAlgorithmParameterException {
+        log.debug("Initializing key for token generator");
+        try {
+            enCipher = Cipher.getInstance(algorithm);
+            deCipher = Cipher.getInstance(algorithm);
+            String[] keyAlg = enCipher.getAlgorithm().split("/");
+            if (keyAlg.length<1) {
+                throw new EncryptionFailedException("Initialization of key 
failed. Not algorithm found.");
+            }
+            String encryptionAlgorithm = keyAlg[0];
+            KeyGenerator keyGen = 
KeyGenerator.getInstance(encryptionAlgorithm);
+            if (keySize>0) {
+                keyGen.init(keySize);
+            }
+            if (keyAlg.length==3 && keyAlg[2].equals("NoPadding")) {
+                paddingUsed=false;
+            }
+            SecretKey secretKey = keyGen.generateKey();
+            enCipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            // We have to provide the IV depending on the algorithm used
+            // CBC needs an IV, ECB not.
+            if (enCipher.getIV()==null) {
+                deCipher.init(Cipher.DECRYPT_MODE, secretKey);
+            } else {
+                deCipher.init(Cipher.DECRYPT_MODE, secretKey, new 
IvParameterSpec(enCipher.getIV()));
+            }
+        } catch (NoSuchAlgorithmException e) {
+            log.error("Error occurred during key initialization. Requested 
algorithm not available. "+e.getMessage());
+            throw e;
+        } catch (NoSuchPaddingException e) {
+            log.error("Error occurred during key initialization. Requested 
padding not available. "+e.getMessage());
+            throw e;
+        } catch (InvalidKeyException e) {
+            log.error("The key is not valid.");
+            throw e;
+        } catch (InvalidAlgorithmParameterException e) {
+            log.error("Invalid encryption parameters.");
+            throw e;
+        }
+    }
+
+
+    @SuppressWarnings("SameParameterValue")
+    public String encryptToken(String user, long lifetime) throws 
EncryptionFailedException {
+        return encryptToken(new SimpleTokenData(user, lifetime, 
createNonce()));
+    }
+
+    public String encryptToken(TokenData tokenData) throws 
EncryptionFailedException {
+        try {
+            return encode(encrypt(tokenData));
+        } catch (IOException e) {
+            log.error("Error during object conversion: "+e.getMessage());
+            throw new EncryptionFailedException(e);
+        } catch (BadPaddingException e) {
+            log.error("Padding invalid");
+            throw new EncryptionFailedException(e);
+        } catch (IllegalBlockSizeException e) {
+            log.error("Block size invalid");
+            throw new EncryptionFailedException(e);
+        }
+    }
+
+    public TokenData decryptToken(String token) throws InvalidTokenException {
+        try {
+            return decrypt(decode(token));
+        } catch (IOException ex) {
+            log.error("Error during data read. " + ex.getMessage());
+            throw new InvalidTokenException(ex);
+        } catch (ClassNotFoundException ex) {
+            log.error("Token data invalid.");
+            throw new InvalidTokenException(ex);
+        } catch (BadPaddingException ex) {
+            log.error("The encrypted token has the wrong padding.");
+            throw new InvalidTokenException(ex);
+        } catch (IllegalBlockSizeException ex) {
+            log.error("The encrypted token has the wrong block size.");
+            throw new InvalidTokenException(ex);
+        }
+    }
+
+    private long createNonce() {
+        return rd.nextLong();
+    }
+
+    protected byte[] encrypt(TokenData info) throws IOException, 
BadPaddingException, IllegalBlockSizeException {
+        return doEncrypt(convertToByteArray(info));
+    }
+
+    protected byte[] doEncrypt(byte[] data) throws BadPaddingException, 
IllegalBlockSizeException {
+        byte[] encData;
+        if (!paddingUsed && (data.length % enCipher.getBlockSize())!=0) {
+            int blocks = data.length / enCipher.getBlockSize();
+            encData = Arrays.copyOf(data, enCipher.getBlockSize()*(blocks+1));
+        } else {
+            encData = data;
+        }
+        return enCipher.doFinal(encData);
+    }
+
+    protected TokenData decrypt(byte[] token) throws BadPaddingException, 
IllegalBlockSizeException, IOException, ClassNotFoundException {
+        Object result = convertFromByteArray(doDecrypt(token));
+        if (!(result instanceof TokenData)) {
+            throw new InvalidClassException("No TokenData found in decrypted 
token");
+        }
+        return (TokenData)result;
+    }
+
+    protected byte[] doDecrypt(byte[] encryptedData) throws 
BadPaddingException, IllegalBlockSizeException {
+        return deCipher.doFinal(encryptedData);
+    }
+
+    private String encode(byte[] token) {
+        return Base64.encodeBase64String(token);
+    }
+
+    private byte[] decode(String token) {
+        return Base64.decodeBase64(token);
+    }
+
+
+    private Object convertFromByteArray(byte[] byteObject) throws IOException,
+            ClassNotFoundException {
+        ByteArrayInputStream bais;
+        ObjectInputStream in;
+        bais = new ByteArrayInputStream(byteObject);
+        in = new ObjectInputStream(bais);
+        Object o = in.readObject();
+        in.close();
+        return o;
+
+    }
+
+
+    private byte[] convertToByteArray(Object complexObject) throws IOException 
{
+        ByteArrayOutputStream baos;
+        ObjectOutputStream out;
+        baos = new ByteArrayOutputStream();
+        out = new ObjectOutputStream(baos);
+        out.writeObject(complexObject);
+        out.close();
+        return baos.toByteArray();
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Sets the encryption algorithm and resets the key size. You may change 
the key size after
+     * calling this method.
+     * Additionally run the initialize() method after setting algorithm and 
keysize.
+     *
+     *
+     * @param algorithm The encryption algorithm to use.
+     */
+    public void setAlgorithm(String algorithm) {
+        if (!this.algorithm.equals(algorithm)) {
+            this.algorithm = algorithm;
+            this.keySize=-1;
+        }
+    }
+
+    public int getKeySize() {
+        return keySize;
+    }
+
+    /**
+     * Sets the key size for the encryption. This method must be called after
+     * setting the algorithm. The keysize will be reset by calling 
<code>setAlgorithm()</code>
+     *
+     * The key size must be valid for the given algorithm.
+     *
+     * @param keySize The size of the encryption key
+     */
+    public void setKeySize(int keySize) {
+        this.keySize = keySize;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/main/resources/META-INF/spring-context.xml
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/main/resources/META-INF/spring-context.xml
 
b/redback-authentication/redback-authentication-api/src/main/resources/META-INF/spring-context.xml
index a07857c..d2aab37 100644
--- 
a/redback-authentication/redback-authentication-api/src/main/resources/META-INF/spring-context.xml
+++ 
b/redback-authentication/redback-authentication-api/src/main/resources/META-INF/spring-context.xml
@@ -30,5 +30,7 @@
   <context:annotation-config />
   <context:component-scan 
     base-package="org.apache.archiva.redback.authentication"/>
- 
+
+  <alias name="tokenManager#jce" alias="tokenManager#default" />
+
 </beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-authentication/redback-authentication-api/src/test/java/org/apache/archiva/redback/authentication/TokenManagerTest.java
----------------------------------------------------------------------
diff --git 
a/redback-authentication/redback-authentication-api/src/test/java/org/apache/archiva/redback/authentication/TokenManagerTest.java
 
b/redback-authentication/redback-authentication-api/src/test/java/org/apache/archiva/redback/authentication/TokenManagerTest.java
new file mode 100644
index 0000000..5200956
--- /dev/null
+++ 
b/redback-authentication/redback-authentication-api/src/test/java/org/apache/archiva/redback/authentication/TokenManagerTest.java
@@ -0,0 +1,153 @@
+package org.apache.archiva.redback.authentication;
+
+/*
+ * 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.
+ */
+
+import org.junit.Test;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test the TokenManager implementation. Uses no spring dependencies.
+ *
+ *  Created by Martin Stockhammer on 11.02.17.
+ */
+public class TokenManagerTest {
+
+    @Test
+    public void initialize() throws NoSuchPaddingException, 
NoSuchAlgorithmException, InvalidKeyException, EncryptionFailedException, 
InvalidAlgorithmParameterException {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.initialize();
+    }
+
+    @Test
+    public void encryptToken() throws Exception {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.initialize();
+        assertEquals(tokenManager.getAlgorithm(),"AES/ECB/PKCS5Padding");
+        assertEquals(tokenManager.getKeySize(), -1);
+        String token = tokenManager.encryptToken("testuser01",1000);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+
+    }
+
+    @Test
+    public void decryptToken() throws Exception {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.initialize();
+        String token = tokenManager.encryptToken("testuser00003",1000);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+        TokenData tokenData = tokenManager.decryptToken(token);
+        assertNotNull(tokenData);
+        assertEquals("testuser00003", tokenData.getUser());
+        assertTrue(tokenData.isValid());
+
+    }
+
+    @Test
+    public void decryptExpiredToken() throws Exception {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.initialize();
+        SimpleTokenData sToken = new SimpleTokenData("testuser00003", 0, 
1345455);
+        String token = tokenManager.encryptToken(sToken);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+        TokenData tokenData = tokenManager.decryptToken(token);
+        assertNotNull(tokenData);
+        assertEquals("testuser00003", tokenData.getUser());
+        assertFalse(tokenData.isValid());
+
+    }
+
+    @Test(expected = InvalidTokenException.class)
+    public void decryptInvalidToken() throws Exception {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.initialize();
+        SimpleTokenData sToken = new SimpleTokenData("testuser00003", 0, 
1345455);
+        String token = tokenManager.encryptToken(sToken);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+        tokenManager.initialize();
+        tokenManager.decryptToken(token);
+
+    }
+
+    @Test
+    public void decryptTokenWithDifferentAlgorithm() throws Exception {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.setAlgorithm("DES/ECB/PKCS5Padding");
+        tokenManager.initialize();
+        String token = tokenManager.encryptToken("testuser00005",2000);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+        TokenData tokenData = tokenManager.decryptToken(token);
+        assertNotNull(tokenData);
+        assertEquals("testuser00005", tokenData.getUser());
+        assertTrue(tokenData.isValid());
+
+
+        tokenManager.setAlgorithm("DES/ECB/NoPadding");
+        tokenManager.initialize();
+        token = tokenManager.encryptToken("testuser00006",2000);
+        assertNotNull(token);
+        assertTrue("Token size too low",token.length()>300);
+        tokenData = tokenManager.decryptToken(token);
+        assertNotNull(tokenData);
+        assertEquals("testuser00006", tokenData.getUser());
+        assertTrue(tokenData.isValid());
+
+    }
+
+    @Test
+    public void nativeEncryption() throws EncryptionFailedException, 
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, 
InvalidAlgorithmParameterException, InvalidTokenException, BadPaddingException, 
IllegalBlockSizeException {
+        TokenManager tokenManager = new TokenManager();
+        tokenManager.setAlgorithm("DES/CBC/PKCS5Padding");
+        tokenManager.setKeySize(56);
+        tokenManager.initialize();
+        byte[] data = { 1, 5, 12, 18, 124, 44, 88, -28, -44};
+        byte[] token = tokenManager.doEncrypt(data);
+        assertNotNull(token);
+        byte[] tokenData = tokenManager.doDecrypt(token);
+        assertNotNull(tokenData);
+        assertArrayEquals(data, tokenData);
+
+
+        tokenManager.setAlgorithm("AES/CBC/NoPadding");
+        tokenManager.setKeySize(128);
+        tokenManager.initialize();
+        token = tokenManager.doEncrypt(data);
+        assertNotNull(token);
+        // Without padding the decrypted value is a multiple of the block size.
+        tokenData = Arrays.copyOf(tokenManager.doDecrypt(token), data.length);
+        assertNotNull(tokenData);
+        assertArrayEquals(data, tokenData);
+
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/User.java
----------------------------------------------------------------------
diff --git 
a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/User.java
 
b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/User.java
index 1b6d50c..2f3e93e 100644
--- 
a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/User.java
+++ 
b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/User.java
@@ -80,6 +80,14 @@ public class User
      */
     private String userManagerId;
 
+    /**
+     * for request validation
+     *
+     * @since 2.2
+     */
+    private String validationToken;
+
+
     public User()
     {
         // no op
@@ -272,6 +280,14 @@ public class User
         this.userManagerId = userManagerId;
     }
 
+    public String getValidationToken() {
+        return validationToken;
+    }
+
+    public void setValidationToken(String validationToken) {
+        this.validationToken = validationToken;
+    }
+
     @Override
     public String toString()
     {

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultLoginService.java
----------------------------------------------------------------------
diff --git 
a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultLoginService.java
 
b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultLoginService.java
index ee3cc47..3bc30bb 100644
--- 
a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultLoginService.java
+++ 
b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultLoginService.java
@@ -22,7 +22,9 @@ package org.apache.archiva.redback.rest.services;
 import org.apache.archiva.redback.authentication.AuthenticationConstants;
 import org.apache.archiva.redback.authentication.AuthenticationException;
 import org.apache.archiva.redback.authentication.AuthenticationFailureCause;
+import org.apache.archiva.redback.authentication.EncryptionFailedException;
 import 
org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
+import org.apache.archiva.redback.authentication.TokenManager;
 import 
org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
 import org.apache.archiva.redback.keys.AuthenticationKey;
 import org.apache.archiva.redback.keys.KeyManager;
@@ -75,6 +77,9 @@ public class DefaultLoginService
     @Context
     private HttpServletRequest httpServletRequest;
 
+    // validation token lifetime: 3 hours
+    long tokenLifetime = 1000*3600*3;
+
     @Inject
     public DefaultLoginService( SecuritySystem securitySystem,
                                 @Named( "httpAuthenticator#basic" ) 
HttpAuthenticator httpAuthenticator )
@@ -149,6 +154,13 @@ public class DefaultLoginService
                 }
                 User restUser = buildRestUser( user );
                 restUser.setReadOnly( securitySystem.userManagerReadOnly() );
+                // validationToken only set during login
+                try {
+                    
restUser.setValidationToken(securitySystem.getTokenManager().encryptToken(user.getUsername(),
 tokenLifetime));
+                } catch (EncryptionFailedException e) {
+                    log.error("Validation token could not be created 
"+e.getMessage());
+                }
+
                 // here create an http session
                 httpAuthenticator.authenticate( authDataSource, 
httpServletRequest.getSession( true ) );
                 return restUser;

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-system/src/main/java/org/apache/archiva/redback/system/DefaultSecuritySystem.java
----------------------------------------------------------------------
diff --git 
a/redback-system/src/main/java/org/apache/archiva/redback/system/DefaultSecuritySystem.java
 
b/redback-system/src/main/java/org/apache/archiva/redback/system/DefaultSecuritySystem.java
index 2f90c79..811903e 100644
--- 
a/redback-system/src/main/java/org/apache/archiva/redback/system/DefaultSecuritySystem.java
+++ 
b/redback-system/src/main/java/org/apache/archiva/redback/system/DefaultSecuritySystem.java
@@ -19,10 +19,12 @@ package org.apache.archiva.redback.system;
  * under the License.
  */
 
+import com.sun.javafx.fxml.expression.Expression;
 import org.apache.archiva.redback.authentication.AuthenticationDataSource;
 import org.apache.archiva.redback.authentication.AuthenticationException;
 import org.apache.archiva.redback.authentication.AuthenticationManager;
 import org.apache.archiva.redback.authentication.AuthenticationResult;
+import org.apache.archiva.redback.authentication.TokenManager;
 import org.apache.archiva.redback.authorization.AuthorizationDataSource;
 import org.apache.archiva.redback.authorization.AuthorizationException;
 import org.apache.archiva.redback.authorization.AuthorizationResult;
@@ -69,6 +71,10 @@ public class DefaultSecuritySystem
     private KeyManager keyManager;
 
     @Inject
+    @Named( value = "tokenManager#default")
+    private TokenManager tokenManager;
+
+    @Inject
     private UserSecurityPolicy policy;
 
     // 
----------------------------------------------------------------------------
@@ -305,4 +311,13 @@ public class DefaultSecuritySystem
         return userManager.isReadOnly();
     }
 
+    @Override
+    public TokenManager getTokenManager() {
+        return tokenManager;
+    }
+
+    public void setTokenManager(TokenManager tokenManager) {
+        this.tokenManager = tokenManager;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/de5816ad/redback-system/src/main/java/org/apache/archiva/redback/system/SecuritySystem.java
----------------------------------------------------------------------
diff --git 
a/redback-system/src/main/java/org/apache/archiva/redback/system/SecuritySystem.java
 
b/redback-system/src/main/java/org/apache/archiva/redback/system/SecuritySystem.java
index c7b049d..f12868a 100644
--- 
a/redback-system/src/main/java/org/apache/archiva/redback/system/SecuritySystem.java
+++ 
b/redback-system/src/main/java/org/apache/archiva/redback/system/SecuritySystem.java
@@ -19,6 +19,7 @@ package org.apache.archiva.redback.system;
  * under the License.
  */
 
+import org.apache.archiva.redback.authentication.TokenManager;
 import org.apache.archiva.redback.policy.AccountLockedException;
 import org.apache.archiva.redback.policy.MustChangePasswordException;
 import org.apache.archiva.redback.policy.UserSecurityPolicy;
@@ -111,5 +112,12 @@ public interface SecuritySystem
      * @since 2.1
      */
     boolean userManagerReadOnly();
+
+    /**
+     * Returns the token manager implementation.
+     *
+     * @since 2.2
+     */
+    TokenManager getTokenManager();
 }
 

Reply via email to