Author: matthieu
Date: Fri Dec 11 10:06:23 2015
New Revision: 1719310

URL: http://svn.apache.org/viewvc?rev=1719310&view=rev
Log:
JAMES-1644 Introduce a ContinuationTokenManager

Added:
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/ContinuationTokenManager.java
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/SignedContinuationTokenManager.java
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/DefaultZonedDateTimeProvider.java
    
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/ZonedDateTimeProvider.java
    
james/project/trunk/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/SignedContinuationTokenManagerTest.java

Added: 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/ContinuationTokenManager.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/ContinuationTokenManager.java?rev=1719310&view=auto
==============================================================================
--- 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/ContinuationTokenManager.java
 (added)
+++ 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/api/ContinuationTokenManager.java
 Fri Dec 11 10:06:23 2015
@@ -0,0 +1,30 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.api;
+
+import org.apache.james.jmap.model.ContinuationToken;
+
+public interface ContinuationTokenManager {
+
+    ContinuationToken generateToken(String username) throws Exception;
+
+    boolean isValid(ContinuationToken token) throws Exception;
+
+}

Added: 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/SignedContinuationTokenManager.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/SignedContinuationTokenManager.java?rev=1719310&view=auto
==============================================================================
--- 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/SignedContinuationTokenManager.java
 (added)
+++ 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/SignedContinuationTokenManager.java
 Fri Dec 11 10:06:23 2015
@@ -0,0 +1,76 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.crypto;
+
+import com.google.common.base.Preconditions;
+import org.apache.james.jmap.api.ContinuationTokenManager;
+import org.apache.james.jmap.model.ContinuationToken;
+import org.apache.james.jmap.utils.ZonedDateTimeProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.SignatureException;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class SignedContinuationTokenManager implements 
ContinuationTokenManager {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(SignedContinuationTokenManager.class);
+
+    private final SignatureHandler signatureHandler;
+    private final ZonedDateTimeProvider zonedDateTimeProvider;
+
+    public SignedContinuationTokenManager(SignatureHandler signatureHandler, 
ZonedDateTimeProvider zonedDateTimeProvider) {
+        this.signatureHandler = signatureHandler;
+        this.zonedDateTimeProvider = zonedDateTimeProvider;
+    }
+
+    @Override
+    public ContinuationToken generateToken(String username) throws Exception {
+        Preconditions.checkNotNull(username);
+        ZonedDateTime expirationTime = 
zonedDateTimeProvider.provide().plusMinutes(15);
+        return new ContinuationToken(username,
+            expirationTime,
+            signatureHandler.sign(username + ContinuationToken.SEPARATOR + 
DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(expirationTime)));
+    }
+
+    @Override
+    public boolean isValid(ContinuationToken token) throws Exception {
+        Preconditions.checkNotNull(token);
+        try {
+            return ! isTokenOutdated(token)
+                && isCorrectlySigned(token);
+        } catch (SignatureException e) {
+            LOGGER.warn("Attempt to use a malformed signature for user " + 
token.getUsername(), e);
+            return false;
+        }
+    }
+
+    private boolean isCorrectlySigned(ContinuationToken token) throws 
Exception {
+        return signatureHandler.verify(token.getUsername()
+            + ContinuationToken.SEPARATOR
+            + 
DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(token.getExpirationDate()),
+            token.getSignature());
+    }
+
+    private boolean isTokenOutdated(ContinuationToken token) {
+        return 
token.getExpirationDate().isBefore(zonedDateTimeProvider.provide());
+    }
+}

Added: 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/DefaultZonedDateTimeProvider.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/DefaultZonedDateTimeProvider.java?rev=1719310&view=auto
==============================================================================
--- 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/DefaultZonedDateTimeProvider.java
 (added)
+++ 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/DefaultZonedDateTimeProvider.java
 Fri Dec 11 10:06:23 2015
@@ -0,0 +1,31 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.utils;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+public class DefaultZonedDateTimeProvider implements ZonedDateTimeProvider {
+
+    @Override
+    public ZonedDateTime provide() {
+        return ZonedDateTime.now(ZoneOffset.UTC);
+    }
+}

Added: 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/ZonedDateTimeProvider.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/ZonedDateTimeProvider.java?rev=1719310&view=auto
==============================================================================
--- 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/ZonedDateTimeProvider.java
 (added)
+++ 
james/project/trunk/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/ZonedDateTimeProvider.java
 Fri Dec 11 10:06:23 2015
@@ -0,0 +1,28 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.utils;
+
+import java.time.ZonedDateTime;
+
+public interface ZonedDateTimeProvider {
+
+    ZonedDateTime provide();
+
+}

Added: 
james/project/trunk/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/SignedContinuationTokenManagerTest.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/SignedContinuationTokenManagerTest.java?rev=1719310&view=auto
==============================================================================
--- 
james/project/trunk/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/SignedContinuationTokenManagerTest.java
 (added)
+++ 
james/project/trunk/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/SignedContinuationTokenManagerTest.java
 Fri Dec 11 10:06:23 2015
@@ -0,0 +1,122 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.crypto;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.james.jmap.model.ContinuationToken;
+import org.apache.james.jmap.utils.ZonedDateTimeProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class SignedContinuationTokenManagerTest {
+
+    private static final String EXPIRATION_DATE_STRING = 
"2011-12-03T10:15:30+01:00";
+    private static final String FAKE_SIGNATURE = 
"MeIFNei4p6vn085wCEw0pbEwJ+Oak5yEIRLZsDcRVzT9rWWOcLvDFUA3S6awi/bxPiFxqJFreVz6xqzehnUI4tUBupk3sIsqeXShhFWBpaV+m58mC41lT/A0RJa3GgCvg6kmweCRf3tOo0+gvwOQJdwCL2B21GjDCKqBHaiK+OHcsSjrQW0xuew5z84EAz3ErdH4MMNjITksxK5FG/cGQ9V6LQgwcPk0RrprVC4eY7FFHw/sQNlJpZKsSFLnn5igPQkQtjiQ4ay1/xoB7FU7aJLakxRhYOnTKgper/Ur7UWOZJaE+4EjcLwCFLF9GaCILwp9W+mf/f7j92PVEU50Vg==";
+    private static final ZonedDateTime DATE = 
ZonedDateTime.parse(EXPIRATION_DATE_STRING, 
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+
+    private SignedContinuationTokenManager toKenManager;
+    private ZonedDateTimeProvider zonedDateTimeProvider;
+
+    @Before
+    public void setUp() throws Exception {
+        JamesSignatureHandler signatureHandler = new 
JamesSignatureHandlerProvider().provide();
+        zonedDateTimeProvider = mock(ZonedDateTimeProvider.class);
+        toKenManager = new SignedContinuationTokenManager(signatureHandler, 
zonedDateTimeProvider);
+    }
+
+    @Test
+    public void isValidShouldRecognizeValidTokens() throws Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        assertThat(
+            toKenManager.isValid(
+                toKenManager.generateToken("user")))
+            .isTrue();
+    }
+
+    @Test
+    public void isValidShouldRecognizeTokenWhereUsernameIsModified() throws 
Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        ContinuationToken continuationToken = 
toKenManager.generateToken("user");
+        ContinuationToken pirateContinuationToken = new 
ContinuationToken("pirate",
+            continuationToken.getExpirationDate(),
+            continuationToken.getSignature());
+        assertThat(toKenManager.isValid(pirateContinuationToken)).isFalse();
+    }
+
+    @Test
+    public void isValidShouldRecognizeTokenWhereExpirationDateIsModified() 
throws Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        ContinuationToken continuationToken = 
toKenManager.generateToken("user");
+        ContinuationToken pirateContinuationToken = new 
ContinuationToken(continuationToken.getUsername(),
+            continuationToken.getExpirationDate().plusHours(1),
+            continuationToken.getSignature());
+        assertThat(toKenManager.isValid(pirateContinuationToken)).isFalse();
+    }
+
+    @Test
+    public void isValidShouldRecognizeTokenWhereSignatureIsModified() throws 
Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        ContinuationToken continuationToken = 
toKenManager.generateToken("user");
+        ContinuationToken pirateContinuationToken = new 
ContinuationToken(continuationToken.getUsername(),
+            continuationToken.getExpirationDate(),
+            FAKE_SIGNATURE);
+        assertThat(toKenManager.isValid(pirateContinuationToken)).isFalse();
+    }
+
+    @Test
+    public void isValidShouldReturnFalseWhenTokenIsOutdated() throws Exception 
{
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        ContinuationToken continuationToken = 
toKenManager.generateToken("user");
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE.plusHours(1));
+        assertThat(toKenManager.isValid(continuationToken)).isFalse();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void generateTokenShouldThrowWhenUsernameIsNull() throws Exception {
+        toKenManager.generateToken(null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void isValidShouldThrowWhenTokenIsNull() throws Exception {
+        toKenManager.isValid(null);
+    }
+
+    @Test
+    public void isValidShouldReturnFalseOnNonValidSignatures() throws 
Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        ContinuationToken pirateContinuationToken = new 
ContinuationToken("user", DATE.plusMinutes(15), "fake");
+        assertThat(toKenManager.isValid(pirateContinuationToken)).isFalse();
+    }
+
+    @Test
+    public void generateTokenShouldHaveTheRightOutPut() throws Exception {
+        when(zonedDateTimeProvider.provide()).thenAnswer(invocationOnMock -> 
DATE);
+        assertThat(toKenManager.generateToken("user").serialize())
+            
.isEqualTo("user_2011-12-03T10:30:30+01:00_eOvOqTmV3dPrhIkbuQSj2sno3YJMxWl6J1sH1JhwYcaNgMX9twm98/WSF9uyDkvJgvBxFokDr53AbxQ3DsJysB2dAzCC0tUM4u8ZMvl/hQrFXhVCdpVMyHRvixKCxnHsVXAr9g3WMn2vbIVq5i3HPgA6/p9FB1+N4WA06B8ueoCrdxT2w1ITEm8p+QZvje3n1F344SgrqgIYqvt0yUvzxnB24f3ccjAKidlBj4wZkcXgUTMbZ7MdnCbDGbp10+tgJqxiv1S0rXZMeJLJ+vBt5TyqEhsJUmUQ84qctlB4yR5FS+ncbAOyZAxs2dWsHqiQjedb3IR77N7CASzqO2mmVw==");
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to