mirror of
https://github.com/google/nomulus
synced 2026-09-06 16:17:13 +00:00
Refactor OIDC-based auth mechanism (#2025)
IAP and regular OIDC auth mechanisms are unified under a base class that produces either APP or USER level AuthResult based on the principal email found in the OIDC token. Also moved some enum classes to better organize code structure.
This commit is contained in:
@@ -27,8 +27,8 @@ import com.google.gson.JsonObject;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Actions;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
|
||||
@@ -32,8 +32,8 @@ import static org.mockito.Mockito.when;
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.common.testing.NullPointerTester;
|
||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.RequestAuthenticator;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import java.util.Optional;
|
||||
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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 google.registry.request.auth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.truth.Truth8;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
/** Tests for {@link IapHeaderAuthenticationMechanism}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
public class IapHeaderAuthenticationMechanismTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final JpaTestExtensions.JpaUnitTestExtension jpaExtension =
|
||||
new JpaTestExtensions.Builder().withEntityClass(User.class).buildUnitTestExtension();
|
||||
|
||||
@Mock private TokenVerifier tokenVerifier;
|
||||
@Mock private HttpServletRequest request;
|
||||
|
||||
private JsonWebSignature token;
|
||||
private IapHeaderAuthenticationMechanism authenticationMechanism;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
authenticationMechanism = new IapHeaderAuthenticationMechanism(tokenVerifier);
|
||||
when(request.getHeader("X-Goog-IAP-JWT-Assertion")).thenReturn("jwtValue");
|
||||
Payload payload = new Payload();
|
||||
payload.setEmail("email@email.com");
|
||||
payload.setSubject("gaiaId");
|
||||
token = new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
when(tokenVerifier.verify("jwtValue")).thenReturn(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_validUser() throws Exception {
|
||||
User user =
|
||||
new User.Builder()
|
||||
.setEmailAddress("email@email.com")
|
||||
.setGaiaId("gaiaId")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
insertInDb(user);
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("idToken", "asdf")});
|
||||
when(tokenVerifier.verify("asdf")).thenReturn(token);
|
||||
AuthResult authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
Truth8.assertThat(authResult.userAuthInfo()).isPresent();
|
||||
Truth8.assertThat(authResult.userAuthInfo().get().consoleUser()).hasValue(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_noCookie() {
|
||||
when(request.getCookies()).thenReturn(new Cookie[0]);
|
||||
assertThat(authenticationMechanism.authenticate(request).isAuthenticated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_badToken() throws Exception {
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("idToken", "asdf")});
|
||||
when(tokenVerifier.verify("asdf")).thenReturn(null);
|
||||
assertThat(authenticationMechanism.authenticate(request).isAuthenticated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_errorVerifyingToken() throws Exception {
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("idToken", "asdf")});
|
||||
when(tokenVerifier.verify("asdf")).thenThrow(new TokenVerifier.VerificationException("hi"));
|
||||
assertThat(authenticationMechanism.authenticate(request).isAuthenticated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_goodTokenButUnknownUser() throws Exception {
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("idToken", "asdf")});
|
||||
when(tokenVerifier.verify("asdf")).thenReturn(token);
|
||||
assertThat(authenticationMechanism.authenticate(request).isAuthenticated()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.testing.FakeClock;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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 google.registry.request.auth;
|
||||
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.request.auth.AuthModule.BEARER_PREFIX;
|
||||
import static google.registry.request.auth.AuthModule.IAP_HEADER_NAME;
|
||||
import static google.registry.request.auth.AuthModule.PROXY_HEADER_NAME;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.auth.oauth2.TokenVerifier.VerificationException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dagger.Component;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.IapOidcAuthenticationMechanism;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.RegularOidcAuthenticationMechanism;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link OidcTokenAuthenticationMechanism}. */
|
||||
public class OidcTokenAuthenticationMechanismTest {
|
||||
|
||||
private static final String rawToken = "this-token";
|
||||
private static final String email = "user@email.test";
|
||||
private static final String gaiaId = "gaia-id";
|
||||
private static final ImmutableList<String> serviceAccounts =
|
||||
ImmutableList.of("service@email.test", "email@service.goog");
|
||||
|
||||
private final Payload payload = new Payload();
|
||||
private final User user =
|
||||
new User.Builder()
|
||||
.setEmailAddress(email)
|
||||
.setGaiaId(gaiaId)
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
private final JsonWebSignature jwt =
|
||||
new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
private final TokenVerifier tokenVerifier = mock(TokenVerifier.class);
|
||||
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
private AuthResult authResult;
|
||||
private OidcTokenAuthenticationMechanism authenticationMechanism =
|
||||
new OidcTokenAuthenticationMechanism(serviceAccounts, tokenVerifier, e -> rawToken) {};
|
||||
|
||||
@RegisterExtension
|
||||
public final JpaTestExtensions.JpaUnitTestExtension jpaExtension =
|
||||
new JpaTestExtensions.Builder().withEntityClass(User.class).buildUnitTestExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
when(tokenVerifier.verify(eq(rawToken))).thenReturn(jwt);
|
||||
payload.setEmail(email);
|
||||
payload.setSubject(gaiaId);
|
||||
insertInDb(user);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
OidcTokenAuthenticationMechanism.unsetAuthResultForTesting();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthResultBypass() {
|
||||
OidcTokenAuthenticationMechanism.setAuthResultForTesting(AuthResult.create(AuthLevel.APP));
|
||||
assertThat(authenticationMechanism.authenticate(null))
|
||||
.isEqualTo(AuthResult.create(AuthLevel.APP));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_noTokenFromRequest() {
|
||||
authenticationMechanism =
|
||||
new OidcTokenAuthenticationMechanism(serviceAccounts, tokenVerifier, e -> null) {};
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_invalidToken() throws Exception {
|
||||
when(tokenVerifier.verify(eq(rawToken))).thenThrow(new VerificationException("Bad token"));
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_noEmailAddress() throws Exception {
|
||||
payload.setEmail(null);
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_user() throws Exception {
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.USER);
|
||||
assertThat(authResult.userAuthInfo().get().consoleUser().get()).isEqualTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_serviceAccount() throws Exception {
|
||||
payload.setEmail("service@email.test");
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.APP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_bothUserAndServiceAccount() throws Exception {
|
||||
User serviceUser =
|
||||
new User.Builder()
|
||||
.setEmailAddress("service@email.test")
|
||||
.setGaiaId("service-gaia-id")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
insertInDb(serviceUser);
|
||||
payload.setEmail("service@email.test");
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.USER);
|
||||
assertThat(authResult.userAuthInfo().get().consoleUser().get()).isEqualTo(serviceUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_unknownEmailAddress() throws Exception {
|
||||
payload.setEmail("bad-guy@evil.real");
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIap_tokenExtractor() throws Exception {
|
||||
useIapOidcMechanism();
|
||||
when(request.getHeader(IAP_HEADER_NAME)).thenReturn(rawToken);
|
||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isEqualTo(rawToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegular_tokenExtractor() throws Exception {
|
||||
useRegularOidcMechanism();
|
||||
// The token does not have the "Bearer " prefix.
|
||||
when(request.getHeader(PROXY_HEADER_NAME)).thenReturn(rawToken);
|
||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isNull();
|
||||
|
||||
// The token is in the correct format.
|
||||
when(request.getHeader(PROXY_HEADER_NAME))
|
||||
.thenReturn(String.format("%s%s", BEARER_PREFIX, rawToken));
|
||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isEqualTo(rawToken);
|
||||
|
||||
// The token is in the correct format, and under the alternative header.
|
||||
when(request.getHeader(PROXY_HEADER_NAME)).thenReturn(null);
|
||||
when(request.getHeader(AUTHORIZATION))
|
||||
.thenReturn(String.format("%s%s", BEARER_PREFIX, rawToken));
|
||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isEqualTo(rawToken);
|
||||
}
|
||||
|
||||
private void useIapOidcMechanism() {
|
||||
TestComponent component = DaggerOidcTokenAuthenticationMechanismTest_TestComponent.create();
|
||||
authenticationMechanism = component.iapOidcAuthenticationMechanism();
|
||||
}
|
||||
|
||||
private void useRegularOidcMechanism() {
|
||||
TestComponent component = DaggerOidcTokenAuthenticationMechanismTest_TestComponent.create();
|
||||
authenticationMechanism = component.regularOidcAuthenticationMechanism();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Component(modules = {AuthModule.class, TestModule.class})
|
||||
interface TestComponent {
|
||||
IapOidcAuthenticationMechanism iapOidcAuthenticationMechanism();
|
||||
|
||||
RegularOidcAuthenticationMechanism regularOidcAuthenticationMechanism();
|
||||
}
|
||||
|
||||
@Module
|
||||
static class TestModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
@Config("projectIdNumber")
|
||||
long provideProjectIdNumber() {
|
||||
return 12345;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Config("projectId")
|
||||
String provideProjectId() {
|
||||
return "my-project";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Config("serviceAccountEmails")
|
||||
ImmutableList<String> provideServiceAccountEmails() {
|
||||
return serviceAccounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,9 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.auth.RequestAuthenticator.AuthMethod;
|
||||
import google.registry.request.auth.RequestAuthenticator.AuthSettings;
|
||||
import google.registry.request.auth.RequestAuthenticator.UserPolicy;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthSettings.AuthMethod;
|
||||
import google.registry.request.auth.AuthSettings.UserPolicy;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeOAuthService;
|
||||
@@ -52,50 +52,42 @@ class RequestAuthenticatorTest {
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL), AuthLevel.NONE, UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_INTERNAL_OR_ADMIN = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_INTERNAL_OR_ADMIN =
|
||||
AuthSettings.create(ImmutableList.of(AuthMethod.INTERNAL), AuthLevel.APP, UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_ANY_USER_ANY_METHOD = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY),
|
||||
AuthLevel.USER,
|
||||
UserPolicy.PUBLIC);
|
||||
private static final AuthSettings AUTH_ANY_USER_ANY_METHOD =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY), AuthLevel.USER, UserPolicy.PUBLIC);
|
||||
|
||||
private static final AuthSettings AUTH_ANY_USER_NO_LEGACY = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API),
|
||||
AuthLevel.USER,
|
||||
UserPolicy.PUBLIC);
|
||||
private static final AuthSettings AUTH_ANY_USER_NO_LEGACY =
|
||||
AuthSettings.create(ImmutableList.of(AuthMethod.API), AuthLevel.USER, UserPolicy.PUBLIC);
|
||||
|
||||
private static final AuthSettings AUTH_ADMIN_USER_ANY_METHOD = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY),
|
||||
AuthLevel.USER,
|
||||
UserPolicy.ADMIN);
|
||||
private static final AuthSettings AUTH_ADMIN_USER_ANY_METHOD =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY), AuthLevel.USER, UserPolicy.ADMIN);
|
||||
|
||||
private static final AuthSettings AUTH_NO_METHODS = AuthSettings.create(
|
||||
ImmutableList.of(),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_NO_METHODS =
|
||||
AuthSettings.create(ImmutableList.of(), AuthLevel.APP, UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_WRONG_METHOD_ORDERING = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.INTERNAL),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_WRONG_METHOD_ORDERING =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.API, AuthMethod.INTERNAL), AuthLevel.APP, UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_DUPLICATE_METHODS = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API, AuthMethod.API),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_DUPLICATE_METHODS =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API, AuthMethod.API),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_INTERNAL_WITH_USER = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API),
|
||||
AuthLevel.USER,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_INTERNAL_WITH_USER =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API),
|
||||
AuthLevel.USER,
|
||||
UserPolicy.IGNORED);
|
||||
|
||||
private static final AuthSettings AUTH_WRONGLY_IGNORING_USER = AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API),
|
||||
AuthLevel.APP,
|
||||
UserPolicy.IGNORED);
|
||||
private static final AuthSettings AUTH_WRONGLY_IGNORING_USER =
|
||||
AuthSettings.create(
|
||||
ImmutableList.of(AuthMethod.INTERNAL, AuthMethod.API), AuthLevel.APP, UserPolicy.IGNORED);
|
||||
|
||||
private final UserService mockUserService = mock(UserService.class);
|
||||
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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 google.registry.request.auth;
|
||||
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class ServiceAccountAuthenticationMechanismTest {
|
||||
|
||||
@Mock private TokenVerifier tokenVerifier;
|
||||
@Mock private HttpServletRequest request;
|
||||
|
||||
private JsonWebSignature token;
|
||||
private ServiceAccountAuthenticationMechanism serviceAccountAuthenticationMechanism;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
serviceAccountAuthenticationMechanism =
|
||||
new ServiceAccountAuthenticationMechanism(
|
||||
tokenVerifier, ImmutableList.of("sa-prefix@email.com", "cloud-tasks@email.com"));
|
||||
when(request.getHeader(AUTHORIZATION)).thenReturn("Bearer jwtValue");
|
||||
Payload payload = new Payload();
|
||||
payload.setEmail("sa-prefix@email.com");
|
||||
token = new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
when(tokenVerifier.verify("jwtValue")).thenReturn(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_authenticates() throws Exception {
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.APP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secondEmail() throws Exception {
|
||||
Payload payload = new Payload();
|
||||
payload.setEmail("cloud-tasks@email.com");
|
||||
token = new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
when(tokenVerifier.verify("jwtValue")).thenReturn(token);
|
||||
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.APP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFails_authenticateWrongEmail() throws Exception {
|
||||
token.getPayload().set("email", "not-service-account-email@email.com");
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFails_authenticateWrongHeader() throws Exception {
|
||||
when(request.getHeader(AUTHORIZATION)).thenReturn("BEARER asd");
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,10 @@ import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import google.registry.request.auth.IapHeaderAuthenticationMechanism;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.testing.UserServiceExtension;
|
||||
import google.registry.tools.params.HostAndPortParameter;
|
||||
@@ -145,7 +148,8 @@ public final class RegistryTestServerMain {
|
||||
.setUserRoles(userRoles)
|
||||
.setRegistryLockPassword("registryLockPassword")
|
||||
.build();
|
||||
IapHeaderAuthenticationMechanism.setUserAuthInfoForTestServer(user);
|
||||
OidcTokenAuthenticationMechanism.setAuthResultForTesting(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user)));
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension().beforeEach(null);
|
||||
JpaTransactionManagerExtension.loadInitialData();
|
||||
System.out.printf("%sLoading fixtures...%s\n", BLUE, RESET);
|
||||
|
||||
+1
-1
@@ -25,8 +25,8 @@ import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeResponse;
|
||||
|
||||
+1
-1
@@ -35,8 +35,8 @@ import google.registry.model.tld.Tld;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
|
||||
+1
-1
@@ -35,8 +35,8 @@ import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
|
||||
@@ -31,8 +31,8 @@ import com.google.common.net.MediaType;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
|
||||
+1
-1
@@ -42,8 +42,8 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationT
|
||||
import google.registry.request.JsonActionRunner;
|
||||
import google.registry.request.JsonResponse;
|
||||
import google.registry.request.ResponseImpl;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
|
||||
+1
-1
@@ -39,8 +39,8 @@ import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.testing.FakeClock;
|
||||
|
||||
+1
-1
@@ -43,8 +43,8 @@ import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import google.registry.request.JsonActionRunner;
|
||||
import google.registry.request.JsonResponse;
|
||||
import google.registry.request.ResponseImpl;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
|
||||
+1
-1
@@ -42,8 +42,8 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
|
||||
Reference in New Issue
Block a user