aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorLukasz Jarocki <lukasz.jarocki@sonarsource.com>2022-04-22 10:37:33 +0200
committersonartech <sonartech@sonarsource.com>2022-04-29 20:03:18 +0000
commite2f49b822078b776bdac89410c191af775a330fe (patch)
tree8b2832a80a4d8ab2dffe791dbf2d898b7a91dbb3 /server
parent52b24b06255c984d5a9638c4e30f16a440dc9217 (diff)
downloadsonarqube-e2f49b822078b776bdac89410c191af775a330fe.tar.gz
sonarqube-e2f49b822078b776bdac89410c191af775a330fe.zip
SONAR-16260 authentication now takes into account token type
Diffstat (limited to 'server')
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BasicAuthentication.java20
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/TokenType.java1
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/UserTokenAuthentication.java98
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/BasicAuthenticationTest.java27
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenAuthenticationTest.java103
5 files changed, 221 insertions, 28 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BasicAuthentication.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BasicAuthentication.java
index 1f6d5ea3399..b5ac6571cba 100644
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BasicAuthentication.java
+++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BasicAuthentication.java
@@ -33,6 +33,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.commons.lang.StringUtils.startsWithIgnoreCase;
import static org.sonar.server.authentication.event.AuthenticationEvent.Method;
import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
+import static org.sonar.server.usertoken.UserTokenAuthentication.PROJECT_KEY_SCANNER_HEADER;
/**
* HTTP BASIC authentication relying on tuple {login, password}.
@@ -43,6 +44,8 @@ import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
*/
public class BasicAuthentication {
+ private static final String ACCESS_LOG_TOKEN_NAME = "TOKEN_NAME";
+
private final DbClient dbClient;
private final CredentialsAuthentication credentialsAuthentication;
private final UserTokenAuthentication userTokenAuthentication;
@@ -94,30 +97,33 @@ public class BasicAuthentication {
}
private UserDto authenticate(Credentials credentials, HttpServletRequest request) {
- if (!credentials.getPassword().isPresent()) {
- UserDto userDto = authenticateFromUserToken(credentials.getLogin());
+ if (credentials.getPassword().isEmpty()) {
+ String projectKeyScannerHeader = request.getHeader(PROJECT_KEY_SCANNER_HEADER);
+ UserDto userDto = authenticateFromUserToken(credentials.getLogin(), request, projectKeyScannerHeader);
authenticationEvent.loginSuccess(request, userDto.getLogin(), Source.local(Method.BASIC_TOKEN));
return userDto;
}
return credentialsAuthentication.authenticate(credentials, request, Method.BASIC);
}
- private UserDto authenticateFromUserToken(String token) {
- Optional<String> authenticatedUserUuid = userTokenAuthentication.authenticate(token);
- if (!authenticatedUserUuid.isPresent()) {
+ private UserDto authenticateFromUserToken(String token, HttpServletRequest request, String projectKey) {
+ String path = request.getRequestURI().substring(request.getContextPath().length());
+ UserTokenAuthentication.UserTokenAuthenticationResult result = userTokenAuthentication.authenticate(token, path, projectKey);
+ if (result.getErrorMessage() != null) {
throw AuthenticationException.newBuilder()
.setSource(Source.local(Method.BASIC_TOKEN))
- .setMessage("Token doesn't exist")
+ .setMessage(result.getErrorMessage())
.build();
}
try (DbSession dbSession = dbClient.openSession(false)) {
- UserDto userDto = dbClient.userDao().selectByUuid(dbSession, authenticatedUserUuid.get());
+ UserDto userDto = dbClient.userDao().selectByUuid(dbSession, result.getAuthenticatedUserUuid());
if (userDto == null || !userDto.isActive()) {
throw AuthenticationException.newBuilder()
.setSource(Source.local(Method.BASIC_TOKEN))
.setMessage("User doesn't exist")
.build();
}
+ request.setAttribute(ACCESS_LOG_TOKEN_NAME, result.getTokenName());
return userDto;
}
}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/TokenType.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/TokenType.java
index 8581b9ad6b6..0fcfbd7626a 100644
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/TokenType.java
+++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/usertoken/TokenType.java
@@ -20,6 +20,7 @@
package org.sonar.server.usertoken;
public enum TokenType {
+
USER_TOKEN("u"),
GLOBAL_ANALYSIS_TOKEN("a"),
PROJECT_ANALYSIS_TOKEN("p");
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 f35e117602a..1bed33677d6 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
@@ -19,16 +19,37 @@
*/
package org.sonar.server.usertoken;
-import java.util.Optional;
+import java.util.EnumMap;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserTokenDto;
import org.sonar.server.authentication.UserLastConnectionDatesUpdater;
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-
public class UserTokenAuthentication {
+
+ public static final String PROJECT_KEY_SCANNER_HEADER = "PROJECT_KEY";
+
+ private static final Set<String> SCANNER_ENDPOINTS = Set.of(
+ "/api/settings/values",
+ "/api/plugins/installed",
+ "/api/project_branches/list",
+ "/api/project_pull_requests/list",
+ "/api/qualityprofiles/search",
+ "/api/rules/search",
+ "/batch/project",
+ "/api/metrics/search",
+ "/api/new_code_periods/show",
+ "/api/ce/submit");
+
+ private static final EnumMap<TokenType, Set<String>> ALLOWLIST_ENDPOINTS_FOR_TOKEN_TYPES = new EnumMap<>(TokenType.class);
+
+ static {
+ ALLOWLIST_ENDPOINTS_FOR_TOKEN_TYPES.put(TokenType.GLOBAL_ANALYSIS_TOKEN, SCANNER_ENDPOINTS);
+ ALLOWLIST_ENDPOINTS_FOR_TOKEN_TYPES.put(TokenType.PROJECT_ANALYSIS_TOKEN, SCANNER_ENDPOINTS);
+ }
+
private final TokenGenerator tokenGenerator;
private final DbClient dbClient;
private final UserLastConnectionDatesUpdater userLastConnectionDatesUpdater;
@@ -40,19 +61,76 @@ public class UserTokenAuthentication {
}
/**
- * Returns the user uuid if the token hash is found, else {@code Optional.absent()}.
- * The returned uuid is not validated. If database is corrupted (table USER_TOKENS badly purged
- * for instance), then the uuid may not relate to a valid user.
+ * Returns the user token details including if the token hash is found and the user has provided valid token type.
+ *
+ * The returned uuid included in the UserTokenAuthenticationResult is not validated. If database is corrupted
+ * (table USER_TOKENS badly purged for instance), then the uuid may not relate to a valid user.
+ *
+ * In case of any issues only the error message is included in UserTokenAuthenticationResult
*/
- public Optional<String> authenticate(String token) {
+ public UserTokenAuthenticationResult authenticate(String token, String requestedEndpoint, @Nullable String analyzedProjectKey) {
String tokenHash = tokenGenerator.hash(token);
try (DbSession dbSession = dbClient.openSession(false)) {
UserTokenDto userToken = dbClient.userTokenDao().selectByTokenHash(dbSession, tokenHash);
if (userToken == null) {
- return empty();
+ return new UserTokenAuthenticationResult("Token doesn't exist");
+ }
+ if (!isValidTokenType(userToken, analyzedProjectKey, requestedEndpoint)) {
+ return new UserTokenAuthenticationResult("Invalid token");
}
userLastConnectionDatesUpdater.updateLastConnectionDateIfNeeded(userToken);
- return of(userToken.getUserUuid());
+ return new UserTokenAuthenticationResult(userToken.getUserUuid(), userToken.getName());
}
}
+
+ private static boolean isValidTokenType(UserTokenDto userToken, @Nullable String analyzedProjectKey, String requestedEndpoint) {
+ TokenType tokenType = TokenType.valueOf(userToken.getType());
+
+ return validateProjectKeyForScannerToken(tokenType, userToken, analyzedProjectKey)
+ && shouldBeAbleToAccessEndpoint(tokenType, requestedEndpoint);
+ }
+
+ private static boolean shouldBeAbleToAccessEndpoint(TokenType tokenType, String requestedEndpoint) {
+ Set<String> allowedEndpoints = ALLOWLIST_ENDPOINTS_FOR_TOKEN_TYPES.get(tokenType);
+ if (allowedEndpoints == null) {
+ return true; // no allowlist configured for the token type - all endpoints are allowed
+ }
+ return allowedEndpoints.stream().anyMatch(requestedEndpoint::startsWith);
+ }
+
+ private static boolean validateProjectKeyForScannerToken(TokenType tokenType, UserTokenDto userToken, @Nullable String analyzedProjectKey) {
+ if (tokenType != TokenType.PROJECT_ANALYSIS_TOKEN) {
+ return true;
+ }
+ return analyzedProjectKey != null && analyzedProjectKey.equals(userToken.getProjectKey());
+ }
+
+ public static class UserTokenAuthenticationResult {
+
+ String authenticatedUserUuid;
+ String errorMessage;
+ String tokenName;
+
+ public UserTokenAuthenticationResult(String authenticatedUserUuid, String tokenName) {
+ this.authenticatedUserUuid = authenticatedUserUuid;
+ this.tokenName = tokenName;
+ }
+
+ public UserTokenAuthenticationResult(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public String getAuthenticatedUserUuid() {
+ return authenticatedUserUuid;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public String getTokenName() {
+ return tokenName;
+ }
+
+ }
}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/BasicAuthenticationTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/BasicAuthenticationTest.java
index d80ff6aa193..05c2231f4c7 100644
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/BasicAuthenticationTest.java
+++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/BasicAuthenticationTest.java
@@ -22,6 +22,7 @@ package org.sonar.server.authentication;
import java.util.Base64;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
@@ -36,14 +37,16 @@ import org.sonar.server.usertoken.UserTokenAuthentication;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC;
import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC_TOKEN;
-import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
public class BasicAuthenticationTest {
@@ -55,6 +58,7 @@ public class BasicAuthenticationTest {
private static final UserDto USER = UserTesting.newUserDto().setLogin(A_LOGIN);
+ private static final String EXAMPLE_ENDPOINT = "/api/ce/submit";
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@@ -70,6 +74,13 @@ public class BasicAuthenticationTest {
private BasicAuthentication underTest = new BasicAuthentication(dbClient, credentialsAuthentication, userTokenAuthentication, authenticationEvent);
+ @Before
+ public void before() {
+ String contextPath = "localhost";
+ when(request.getRequestURI()).thenReturn(contextPath + EXAMPLE_ENDPOINT);
+ when(request.getContextPath()).thenReturn(contextPath);
+ }
+
@Test
public void authenticate_from_basic_http_header() {
when(request.getHeader("Authorization")).thenReturn("Basic " + CREDENTIALS_IN_BASE64);
@@ -134,7 +145,8 @@ public class BasicAuthenticationTest {
@Test
public void authenticate_from_user_token() {
UserDto user = db.users().insertUser();
- when(userTokenAuthentication.authenticate("token")).thenReturn(Optional.of(user.getUuid()));
+ var result = new UserTokenAuthentication.UserTokenAuthenticationResult(user.getUuid(), "my-token");
+ when(userTokenAuthentication.authenticate("token", EXAMPLE_ENDPOINT, null)).thenReturn(result);
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
Optional<UserDto> userAuthenticated = underTest.authenticate(request);
@@ -142,11 +154,13 @@ public class BasicAuthenticationTest {
assertThat(userAuthenticated).isPresent();
assertThat(userAuthenticated.get().getLogin()).isEqualTo(user.getLogin());
verify(authenticationEvent).loginSuccess(request, user.getLogin(), Source.local(BASIC_TOKEN));
+ verify(request).setAttribute("TOKEN_NAME", "my-token");
}
@Test
public void does_not_authenticate_from_user_token_when_token_is_invalid() {
- when(userTokenAuthentication.authenticate("token")).thenReturn(Optional.empty());
+ var result = new UserTokenAuthentication.UserTokenAuthenticationResult("Token doesn't exist");
+ when(userTokenAuthentication.authenticate("token", EXAMPLE_ENDPOINT, null)).thenReturn(result);
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
assertThatThrownBy(() -> underTest.authenticate(request))
@@ -155,11 +169,13 @@ public class BasicAuthenticationTest {
.hasFieldOrPropertyWithValue("source", Source.local(BASIC_TOKEN));
verifyNoInteractions(authenticationEvent);
+ verify(request, times(0)).setAttribute(anyString(), anyString());
}
@Test
public void does_not_authenticate_from_user_token_when_token_does_not_match_existing_user() {
- when(userTokenAuthentication.authenticate("token")).thenReturn(Optional.of("Unknown user"));
+ var result = new UserTokenAuthentication.UserTokenAuthenticationResult("unknown-user-uuid", "my-token");
+ when(userTokenAuthentication.authenticate("token", EXAMPLE_ENDPOINT, null)).thenReturn(result);
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
assertThatThrownBy(() -> underTest.authenticate(request))
@@ -173,7 +189,8 @@ public class BasicAuthenticationTest {
@Test
public void does_not_authenticate_from_user_token_when_token_does_not_match_active_user() {
UserDto user = db.users().insertDisabledUser();
- when(userTokenAuthentication.authenticate("token")).thenReturn(Optional.of(user.getUuid()));
+ var result = new UserTokenAuthentication.UserTokenAuthenticationResult(user.getUuid(), "my-token");
+ when(userTokenAuthentication.authenticate("token", EXAMPLE_ENDPOINT, null)).thenReturn(result);
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
assertThatThrownBy(() -> underTest.authenticate(request))
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 20453ccdb31..7957812dab1 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,7 +19,7 @@
*/
package org.sonar.server.usertoken;
-import java.util.Optional;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
@@ -27,6 +27,7 @@ import org.sonar.db.DbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTokenDto;
import org.sonar.server.authentication.UserLastConnectionDatesUpdater;
+import org.sonar.server.usertoken.UserTokenAuthentication.UserTokenAuthenticationResult;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -37,6 +38,20 @@ import static org.mockito.Mockito.when;
public class UserTokenAuthenticationTest {
+ private static final String EXAMPLE_SCANNER_ENDPOINT = "/api/settings/values.protobuf";
+ private static final String EXAMPLE_USER_ENDPOINT = "/api/editions/set_license";
+
+ private static final String EXAMPLE_PROJECT_KEY = "my-project-key";
+
+ private static final String EXAMPLE_OLD_USER_TOKEN = "StringWith40CharactersThatIsOldUserToken";
+ private static final String EXAMPLE_NEW_USER_TOKEN = "squ_StringWith44CharactersThatIsNewUserToken";
+ private static final String EXAMPLE_GLOBAL_ANALYSIS_TOKEN = "sqa_StringWith44CharactersWhichIsGlobalToken";
+ private static final String EXAMPLE_PROJECT_ANALYSIS_TOKEN = "sqp_StringWith44CharactersThatIsProjectToken";
+
+ private static final String OLD_USER_TOKEN_HASH = "old-user-token-hash";
+ private static final String NEW_USER_TOKEN_HASH = "new-user-token-hash";
+ private static final String PROJECT_ANALYSIS_TOKEN_HASH = "project-analysis-token-hash";
+ private static final String GLOBAL_ANALYSIS_TOKEN_HASH = "global-analysis-token-hash";
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@@ -46,6 +61,14 @@ public class UserTokenAuthenticationTest {
private UserTokenAuthentication underTest = new UserTokenAuthentication(tokenGenerator, db.getDbClient(), userLastConnectionDatesUpdater);
+ @Before
+ public void before() {
+ when(tokenGenerator.hash(EXAMPLE_OLD_USER_TOKEN)).thenReturn(OLD_USER_TOKEN_HASH);
+ when(tokenGenerator.hash(EXAMPLE_NEW_USER_TOKEN)).thenReturn(NEW_USER_TOKEN_HASH);
+ when(tokenGenerator.hash(EXAMPLE_PROJECT_ANALYSIS_TOKEN)).thenReturn(PROJECT_ANALYSIS_TOKEN_HASH);
+ when(tokenGenerator.hash(EXAMPLE_GLOBAL_ANALYSIS_TOKEN)).thenReturn(GLOBAL_ANALYSIS_TOKEN_HASH);
+ }
+
@Test
public void return_login_when_token_hash_found_in_db() {
String token = "known-token";
@@ -56,19 +79,87 @@ public class UserTokenAuthenticationTest {
UserDto user2 = db.users().insertUser();
db.users().insertToken(user2, t -> t.setTokenHash("another-token-hash"));
- Optional<String> login = underTest.authenticate(token);
+ UserTokenAuthenticationResult result = underTest.authenticate(token, EXAMPLE_USER_ENDPOINT, null);
- assertThat(login)
- .isPresent()
+ assertThat(result.getAuthenticatedUserUuid())
+ .isNotNull()
.contains(user1.getUuid());
verify(userLastConnectionDatesUpdater).updateLastConnectionDateIfNeeded(any(UserTokenDto.class));
}
@Test
public void return_absent_if_token_hash_is_not_found() {
- Optional<String> login = underTest.authenticate("unknown-token");
+ var result = underTest.authenticate(EXAMPLE_OLD_USER_TOKEN, EXAMPLE_USER_ENDPOINT, null);
- assertThat(login).isEmpty();
+ assertThat(result.getAuthenticatedUserUuid()).isNull();
verify(userLastConnectionDatesUpdater, never()).updateLastConnectionDateIfNeeded(any(UserTokenDto.class));
}
+
+ @Test
+ public void authenticate_givenProjectTokenAndUserEndpoint_fillErrorMessage() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(PROJECT_ANALYSIS_TOKEN_HASH).setType(TokenType.PROJECT_ANALYSIS_TOKEN.name()));
+
+ var authenticate = underTest.authenticate(EXAMPLE_PROJECT_ANALYSIS_TOKEN, EXAMPLE_USER_ENDPOINT, EXAMPLE_PROJECT_KEY);
+
+ assertThat(authenticate.getErrorMessage()).isNotNull().contains("Invalid token");
+ }
+
+ @Test
+ public void authenticate_givenProjectTokenAndUserEndpoint_InvalidTokenErrorMessage() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(PROJECT_ANALYSIS_TOKEN_HASH).setType(TokenType.PROJECT_ANALYSIS_TOKEN.name()));
+
+ var result = underTest.authenticate(EXAMPLE_PROJECT_ANALYSIS_TOKEN, EXAMPLE_USER_ENDPOINT, EXAMPLE_PROJECT_KEY);
+
+ assertThat(result.getErrorMessage()).isNotNull().contains("Invalid token");
+ }
+
+ @Test
+ public void authenticate_givenGlobalTokenAndScannerEndpoint_resultContainsUuid() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(GLOBAL_ANALYSIS_TOKEN_HASH).setType(TokenType.GLOBAL_ANALYSIS_TOKEN.name()));
+
+ var result = underTest.authenticate(EXAMPLE_GLOBAL_ANALYSIS_TOKEN, EXAMPLE_SCANNER_ENDPOINT, EXAMPLE_PROJECT_KEY);
+
+ assertThat(result.getAuthenticatedUserUuid()).isNotNull();
+ assertThat(result.getErrorMessage()).isNull();
+ }
+
+ @Test
+ public void authenticate_givenNewUserTokenAndScannerEndpoint_resultContainsUuid() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(NEW_USER_TOKEN_HASH).setType(TokenType.USER_TOKEN.name()));
+
+ var result = underTest.authenticate(EXAMPLE_NEW_USER_TOKEN, EXAMPLE_SCANNER_ENDPOINT, null);
+
+ assertThat(result.getAuthenticatedUserUuid()).isNotNull();
+ assertThat(result.getErrorMessage()).isNull();
+ }
+
+ @Test
+ public void authenticate_givenProjectTokenAndScannerEndpointAndValidProjectKey_resultContainsUuid() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(PROJECT_ANALYSIS_TOKEN_HASH)
+ .setProjectKey("project-key")
+ .setType(TokenType.PROJECT_ANALYSIS_TOKEN.name()));
+
+ var result = underTest.authenticate(EXAMPLE_PROJECT_ANALYSIS_TOKEN, EXAMPLE_SCANNER_ENDPOINT, "project-key");
+
+ assertThat(result.getAuthenticatedUserUuid()).isNotNull();
+ assertThat(result.getErrorMessage()).isNull();
+ }
+
+ @Test
+ public void authenticate_givenProjectTokenAndScannerEndpointAndWrongProjectKey_resultContainsErrorMessage() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setTokenHash(PROJECT_ANALYSIS_TOKEN_HASH)
+ .setProjectKey("project-key")
+ .setType(TokenType.PROJECT_ANALYSIS_TOKEN.name()));
+
+ var result = underTest.authenticate(EXAMPLE_PROJECT_ANALYSIS_TOKEN, EXAMPLE_SCANNER_ENDPOINT, "project-key-2");
+
+ assertThat(result.getAuthenticatedUserUuid()).isNull();
+ assertThat(result.getErrorMessage()).isNotNull();
+ }
}