aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-auth
diff options
context:
space:
mode:
authorMatteo Mara <matteo.mara@sonarsource.com>2022-06-30 10:44:29 +0200
committersonartech <sonartech@sonarsource.com>2022-07-01 20:03:06 +0000
commit5159eb8d7cda29c357aa06868a595d07fbc6f633 (patch)
tree7caf459539e67ed23199256d6df9ba18911ee069 /server/sonar-webserver-auth
parent05ebcc134533b03a324a2710c3fe6d711850a5c4 (diff)
downloadsonarqube-5159eb8d7cda29c357aa06868a595d07fbc6f633.tar.gz
sonarqube-5159eb8d7cda29c357aa06868a595d07fbc6f633.zip
SONAR-16565 handle token expiration at the authentication level
Diffstat (limited to 'server/sonar-webserver-auth')
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java6
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java46
2 files changed, 50 insertions, 2 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java
index be066b6a422..8bdef338bf6 100644
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java
+++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java
@@ -33,6 +33,7 @@ import org.sonar.server.authentication.event.AuthenticationEvent;
import org.sonar.server.authentication.event.AuthenticationException;
import org.sonar.server.exceptions.NotFoundException;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.server.authentication.BasicAuthentication.extractCredentialsFromHeader;
public class UserTokenAuthentication {
@@ -80,7 +81,7 @@ public class UserTokenAuthentication {
}
request.setAttribute(ACCESS_LOG_TOKEN_NAME, userToken.getName());
return new UserAuthResult(userDto, userToken, UserAuthResult.AuthType.TOKEN);
- } catch (NotFoundException exception) {
+ } catch (NotFoundException | IllegalStateException exception ) {
throw AuthenticationException.newBuilder()
.setSource(AuthenticationEvent.Source.local(AuthenticationEvent.Method.BASIC_TOKEN))
.setMessage(exception.getMessage())
@@ -93,6 +94,9 @@ public class UserTokenAuthentication {
if (userToken == null) {
throw new NotFoundException("Token doesn't exist");
}
+ if (userToken.isExpired()) {
+ throw new IllegalStateException("The token expired on " + formatDateTime(userToken.getExpirationDate()));
+ }
userLastConnectionDatesUpdater.updateLastConnectionDateIfNeeded(userToken);
return userToken;
}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java
index 3e353f20e28..44d3cc141d8 100644
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java
+++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java
@@ -19,6 +19,8 @@
*/
package org.sonar.server.usertoken;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
import java.util.Base64;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
@@ -43,6 +45,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.db.user.TokenType.GLOBAL_ANALYSIS_TOKEN;
import static org.sonar.db.user.TokenType.PROJECT_ANALYSIS_TOKEN;
import static org.sonar.db.user.TokenType.USER_TOKEN;
@@ -105,6 +108,30 @@ public class UserTokenAuthenticationTest {
}
@Test
+ public void return_login_when_token_hash_found_in_db_and_future_expiration_date() {
+ String token = "known-token";
+ String tokenHash = "123456789";
+
+ long expirationTimestamp = ZonedDateTime.now(ZoneId.systemDefault()).plusDays(10).toInstant().toEpochMilli();
+ when(request.getHeader(AUTHORIZATION_HEADER)).thenReturn("Basic " + toBase64(token + ":"));
+ when(tokenGenerator.hash(token)).thenReturn(tokenHash);
+ UserDto user1 = db.users().insertUser();
+ UserTokenDto userTokenDto = db.users().insertToken(user1, t -> t.setTokenHash(tokenHash).setExpirationDate(expirationTimestamp));
+ UserDto user2 = db.users().insertUser();
+ db.users().insertToken(user2, t -> t.setTokenHash("another-token-hash"));
+
+ Optional<UserAuthResult> result = underTest.authenticate(request);
+
+ assertThat(result).isPresent();
+ assertThat(result.get().getTokenDto().getUuid()).isEqualTo(userTokenDto.getUuid());
+ assertThat(result.get().getTokenDto().getExpirationDate()).isEqualTo(expirationTimestamp);
+ assertThat(result.get().getUserDto().getUuid())
+ .isNotNull()
+ .contains(user1.getUuid());
+ verify(userLastConnectionDatesUpdater).updateLastConnectionDateIfNeeded(any(UserTokenDto.class));
+ }
+
+ @Test
public void return_absent_if_username_password_used() {
when(request.getHeader(AUTHORIZATION_HEADER)).thenReturn("Basic " + toBase64("login:password"));
@@ -116,7 +143,7 @@ public class UserTokenAuthenticationTest {
}
@Test
- public void return_absent_if_token_hash_is_not_found() {
+ public void throw_authentication_exception_if_token_hash_is_not_found() {
when(request.getHeader(AUTHORIZATION_HEADER)).thenReturn("Basic " + toBase64(EXAMPLE_OLD_USER_TOKEN + ":"));
assertThatThrownBy(() -> underTest.authenticate(request))
@@ -127,6 +154,23 @@ public class UserTokenAuthenticationTest {
}
@Test
+ public void throw_authentication_exception_if_token_is_expired() {
+ String token = "known-token";
+ String tokenHash = "123456789";
+ long expirationTimestamp = System.currentTimeMillis();
+ when(request.getHeader(AUTHORIZATION_HEADER)).thenReturn("Basic " + toBase64(token + ":"));
+ when(tokenGenerator.hash(token)).thenReturn(tokenHash);
+ UserDto user1 = db.users().insertUser();
+ db.users().insertToken(user1, t -> t.setTokenHash(tokenHash).setExpirationDate(expirationTimestamp));
+
+ assertThatThrownBy(() -> underTest.authenticate(request))
+ .hasMessageContaining("The token expired on " + formatDateTime(expirationTimestamp))
+ .isInstanceOf(AuthenticationException.class);
+ verify(userLastConnectionDatesUpdater, never()).updateLastConnectionDateIfNeeded(any(UserTokenDto.class));
+ verifyNoInteractions(authenticationEvent);
+ }
+
+ @Test
public void authenticate_givenGlobalToken_resultContainsUuid() {
UserDto user = db.users().insertUser();
String tokenName = db.users().insertToken(user, t -> t.setTokenHash(GLOBAL_ANALYSIS_TOKEN_HASH).setType(GLOBAL_ANALYSIS_TOKEN.name())).getName();