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]