mirror of
https://github.com/google/nomulus.git
synced 2025-07-23 19:20:44 +02:00
Remove OAuthAuthenticationMechanism (#2171)
Also made some refactoring to various Auth related classes to clean up things a bit and make the logic less convoluted: 1. In Auth, remove AUTH_API_PUBLIC as it is only used by the WHOIS and EPP endpoints accessed by the proxy. Previously, the proxy relies on OAuth and its service account is not given admin role (in OAuth parlance), so we made them accessible by a public user, deferring authorization to the actions themselves. In practice, OAuth checks for allowlisted client IDs and only the proxy client ID was allowlisted, which effectively limited access to only the proxy anyway. 2. In AuthResult, expose the service account email if it is at APP level. RequestAuthenticator will print out the auth result and therefore log the email, making it easy to identify which account was used. This field is mutually exclusive to the user auth info field. As a result, the factory methods are refactored to explicitly create either APP or USER level auth result. 3. Completely re-wrote RequestAuthenticatorTest. Previously, the test mingled testing functionalities of the target class with testing how various authentication mechanisms work. Now they are cleanly decoupled, and each method in RequestAuthenticator is tested individually. 4. Removed nomulus-config-production-sample.yaml as it is vastly out of date.
This commit is contained in:
parent
bbdbfe85ed
commit
36bd508bf9
49 changed files with 365 additions and 1098 deletions
|
@ -1174,44 +1174,6 @@ public final class RegistryConfig {
|
||||||
return CONFIG_SETTINGS.get();
|
return CONFIG_SETTINGS.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the OAuth scopes that authentication logic should detect on access tokens.
|
|
||||||
*
|
|
||||||
* <p>This list should be a superset of the required OAuth scope set provided below. Note that
|
|
||||||
* ideally, this setting would not be required and all scopes on an access token would be
|
|
||||||
* detected automatically, but that is not the case due to the way {@code OAuthService} works.
|
|
||||||
*
|
|
||||||
* <p>This is an independent setting from the required OAuth scopes (below) to support use cases
|
|
||||||
* where certain actions require some additional scope (e.g. access to a user's Google Drive)
|
|
||||||
* but that scope shouldn't be required for authentication alone; in that case the Drive scope
|
|
||||||
* would be specified only for this setting, allowing that action to check for its presence.
|
|
||||||
*/
|
|
||||||
@Provides
|
|
||||||
@Config("availableOauthScopes")
|
|
||||||
public static ImmutableSet<String> provideAvailableOauthScopes(RegistryConfigSettings config) {
|
|
||||||
return ImmutableSet.copyOf(config.auth.availableOauthScopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the OAuth scopes that are required for authenticating successfully.
|
|
||||||
*
|
|
||||||
* <p>This set contains the scopes which must be present to authenticate a user. It should be a
|
|
||||||
* subset of the scopes we request from the OAuth interface, provided above.
|
|
||||||
*
|
|
||||||
* <p>If we feel the need, we could define additional fixed scopes, similar to the Java remote
|
|
||||||
* API, which requires at least one of:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code https://www.googleapis.com/auth/appengine.apis}
|
|
||||||
* <li>{@code https://www.googleapis.com/auth/cloud-platform}
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
@Provides
|
|
||||||
@Config("requiredOauthScopes")
|
|
||||||
public static ImmutableSet<String> provideRequiredOauthScopes(RegistryConfigSettings config) {
|
|
||||||
return ImmutableSet.copyOf(config.auth.requiredOauthScopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides service account email addresses allowed to authenticate with the app at {@link
|
* Provides service account email addresses allowed to authenticate with the app at {@link
|
||||||
* google.registry.request.auth.AuthSettings.AuthLevel#APP} level.
|
* google.registry.request.auth.AuthSettings.AuthLevel#APP} level.
|
||||||
|
@ -1223,13 +1185,6 @@ public final class RegistryConfig {
|
||||||
return ImmutableSet.copyOf(config.auth.allowedServiceAccountEmails);
|
return ImmutableSet.copyOf(config.auth.allowedServiceAccountEmails);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides the allowed OAuth client IDs (could be multibinding). */
|
|
||||||
@Provides
|
|
||||||
@Config("allowedOauthClientIds")
|
|
||||||
public static ImmutableSet<String> provideAllowedOauthClientIds(RegistryConfigSettings config) {
|
|
||||||
return ImmutableSet.copyOf(config.auth.allowedOauthClientIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Config("oauthClientId")
|
@Config("oauthClientId")
|
||||||
public static String provideOauthClientId(RegistryConfigSettings config) {
|
public static String provideOauthClientId(RegistryConfigSettings config) {
|
||||||
|
|
|
@ -58,9 +58,6 @@ public class RegistryConfigSettings {
|
||||||
|
|
||||||
/** Configuration options for authenticating users. */
|
/** Configuration options for authenticating users. */
|
||||||
public static class Auth {
|
public static class Auth {
|
||||||
public List<String> availableOauthScopes;
|
|
||||||
public List<String> requiredOauthScopes;
|
|
||||||
public List<String> allowedOauthClientIds;
|
|
||||||
public List<String> allowedServiceAccountEmails;
|
public List<String> allowedServiceAccountEmails;
|
||||||
public String oauthClientId;
|
public String oauthClientId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,24 +304,6 @@ caching:
|
||||||
# Note: Only allowedServiceAccountEmails and oauthClientId should be configured.
|
# Note: Only allowedServiceAccountEmails and oauthClientId should be configured.
|
||||||
# Other fields are related to OAuth-based authentication and will be removed.
|
# Other fields are related to OAuth-based authentication and will be removed.
|
||||||
auth:
|
auth:
|
||||||
# Deprecated: Use OIDC-based auth instead. This field is for OAuth-based auth.
|
|
||||||
# OAuth scopes to detect on access tokens. Superset of requiredOauthScopes.
|
|
||||||
availableOauthScopes:
|
|
||||||
- https://www.googleapis.com/auth/userinfo.email
|
|
||||||
|
|
||||||
# Deprecated: Use OIDC-based auth instead. This field is for OAuth-based auth.
|
|
||||||
# OAuth scopes required for authenticating. Subset of availableOauthScopes.
|
|
||||||
requiredOauthScopes:
|
|
||||||
- https://www.googleapis.com/auth/userinfo.email
|
|
||||||
|
|
||||||
# Deprecated: Use OIDC-based auth instead. This field is for OAuth-based auth.
|
|
||||||
# OAuth client IDs that are allowed to authenticate and communicate with
|
|
||||||
# backend services, e.g. nomulus tool, EPP proxy, etc. The value in
|
|
||||||
# registryTool.clientId field should be included in this list. Client IDs are
|
|
||||||
# typically of the format
|
|
||||||
# numbers-alphanumerics.apps.googleusercontent.com
|
|
||||||
allowedOauthClientIds: []
|
|
||||||
|
|
||||||
# Service accounts (e.g. default service account, account used by Cloud
|
# Service accounts (e.g. default service account, account used by Cloud
|
||||||
# Scheduler) allowed to send authenticated requests.
|
# Scheduler) allowed to send authenticated requests.
|
||||||
allowedServiceAccountEmails:
|
allowedServiceAccountEmails:
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
# This is a sample production config (to be deployed in the WEB-INF directory).
|
|
||||||
# This is the same as what Google Registry runs in production, except with
|
|
||||||
# placeholders for Google-specific settings.
|
|
||||||
|
|
||||||
gcpProject:
|
|
||||||
projectId: placeholder
|
|
||||||
# Set to true if running against local servers (localhost)
|
|
||||||
isLocal: false
|
|
||||||
# The "<service>-dot-" prefix is used on the project ID in this URL in order
|
|
||||||
# to get around an issue with double-wildcard SSL certs.
|
|
||||||
defaultServiceUrl: https://domain-registry-placeholder.appspot.com
|
|
||||||
backendServiceUrl: https://backend-dot-domain-registry-placeholder.appspot.com
|
|
||||||
toolsServiceUrl: https://tools-dot-domain-registry-placeholder.appspot.com
|
|
||||||
pubapiServiceUrl: https://pubapi-dot-domain-registry-placeholder.appspot.com
|
|
||||||
|
|
||||||
gSuite:
|
|
||||||
domainName: placeholder
|
|
||||||
outgoingEmailDisplayName: placeholder
|
|
||||||
outgoingEmailAddress: placeholder
|
|
||||||
adminAccountEmailAddress: placeholder
|
|
||||||
supportGroupEmailAddress: placeholder
|
|
||||||
|
|
||||||
registryPolicy:
|
|
||||||
contactAndHostRoidSuffix: placeholder
|
|
||||||
productName: placeholder
|
|
||||||
greetingServerId: placeholder
|
|
||||||
registrarChangesNotificationEmailAddresses:
|
|
||||||
- placeholder
|
|
||||||
- placeholder
|
|
||||||
defaultRegistrarWhoisServer: placeholder
|
|
||||||
tmchCaMode: PRODUCTION
|
|
||||||
tmchCrlUrl: http://crl.icann.org/tmch.crl
|
|
||||||
tmchMarksDbUrl: https://ry.marksdb.org
|
|
||||||
checkApiServletClientId: placeholder
|
|
||||||
registryAdminClientId: placeholder
|
|
||||||
whoisDisclaimer: |
|
|
||||||
multi-line
|
|
||||||
placeholder
|
|
||||||
|
|
||||||
icannReporting:
|
|
||||||
icannTransactionsReportingUploadUrl: https://ry-api.icann.org/report/registrar-transactions
|
|
||||||
icannActivityReportingUploadUrl: https://ry-api.icann.org/report/registry-functions-activity
|
|
||||||
|
|
||||||
oAuth:
|
|
||||||
allowedOauthClientIds:
|
|
||||||
- placeholder.apps.googleusercontent.com
|
|
||||||
- placeholder-for-proxy
|
|
||||||
|
|
||||||
rde:
|
|
||||||
reportUrlPrefix: https://ry-api.icann.org/report/registry-escrow-report
|
|
||||||
uploadUrl: sftp://placeholder@sftpipm2.ironmountain.com/Outbox
|
|
||||||
sshIdentityEmailAddress: placeholder
|
|
||||||
|
|
||||||
registrarConsole:
|
|
||||||
logoFilename: placeholder
|
|
||||||
supportPhoneNumber: placeholder
|
|
||||||
supportEmailAddress: placeholder
|
|
||||||
announcementsEmailAddress: placeholder
|
|
||||||
integrationEmailAddress: placeholder
|
|
||||||
technicalDocsUrl: https://drive.google.com/drive/folders/placeholder
|
|
||||||
|
|
||||||
misc:
|
|
||||||
sheetExportId: placeholder
|
|
||||||
|
|
||||||
cloudDns:
|
|
||||||
rootUrl: null
|
|
||||||
servicePath: null
|
|
||||||
|
|
||||||
keyring:
|
|
||||||
activeKeyring: KMS
|
|
||||||
kms:
|
|
||||||
projectId: placeholder
|
|
||||||
|
|
||||||
registryTool:
|
|
||||||
clientId: placeholder.apps.googleusercontent.com
|
|
||||||
clientSecret: placeholder
|
|
|
@ -29,7 +29,7 @@ import javax.servlet.http.HttpSession;
|
||||||
service = Action.Service.DEFAULT,
|
service = Action.Service.DEFAULT,
|
||||||
path = "/_dr/epp",
|
path = "/_dr/epp",
|
||||||
method = Method.POST,
|
method = Method.POST,
|
||||||
auth = Auth.AUTH_API_PUBLIC)
|
auth = Auth.AUTH_API_ADMIN)
|
||||||
public class EppTlsAction implements Runnable {
|
public class EppTlsAction implements Runnable {
|
||||||
|
|
||||||
@Inject @Payload byte[] inputXmlBytes;
|
@Inject @Payload byte[] inputXmlBytes;
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
package google.registry.request.auth;
|
package google.registry.request.auth;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import google.registry.flows.EppTlsAction;
|
|
||||||
import google.registry.flows.TlsCredentials;
|
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||||
import google.registry.request.auth.AuthSettings.AuthMethod;
|
import google.registry.request.auth.AuthSettings.AuthMethod;
|
||||||
import google.registry.request.auth.AuthSettings.UserPolicy;
|
import google.registry.request.auth.AuthSettings.UserPolicy;
|
||||||
|
@ -48,30 +46,18 @@ public enum Auth {
|
||||||
* Allows anyone to access, as long as they are logged in.
|
* Allows anyone to access, as long as they are logged in.
|
||||||
*
|
*
|
||||||
* <p>This is used by legacy registrar console programmatic endpoints (those that extend {@link
|
* <p>This is used by legacy registrar console programmatic endpoints (those that extend {@link
|
||||||
* JsonGetAction}, which are accessed via XHR requests sent from a logged-in user when performing
|
* JsonGetAction}), which are accessed via XHR requests sent from a logged-in user when performing
|
||||||
* actions on the console.
|
* actions on the console.
|
||||||
*/
|
*/
|
||||||
AUTH_PUBLIC_LOGGED_IN(
|
AUTH_PUBLIC_LOGGED_IN(
|
||||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY), AuthLevel.USER, UserPolicy.PUBLIC),
|
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY), AuthLevel.USER, UserPolicy.PUBLIC),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows any client to access, as long as they are logged in via API-based authentication
|
* Allows only the app itself (via service accounts) or admins to access.
|
||||||
* mechanisms.
|
|
||||||
*
|
*
|
||||||
* <p>This is used by the proxy to access Nomulus endpoints. The proxy service account does NOT
|
* <p>This applies to the majority of the endpoints. For APP level authentication to work, the
|
||||||
* have admin privileges. For EPP, we handle client authentication within {@link EppTlsAction},
|
* associated service account needs to be allowlisted in the {@code
|
||||||
* using {@link TlsCredentials}. For WHOIS, anyone connecting to the proxy can access.
|
* auth.allowedServiceAccountEmails} field in the config YAML file.
|
||||||
*
|
|
||||||
* <p>Note that the proxy service account DOES need to be allow-listed in the {@code
|
|
||||||
* auth.allowedServiceAccountEmails} field in the config YAML file in order for OIDC-based
|
|
||||||
* authentication to pass.
|
|
||||||
*/
|
|
||||||
AUTH_API_PUBLIC(ImmutableList.of(AuthMethod.API), AuthLevel.APP, UserPolicy.PUBLIC),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows only admins to access.
|
|
||||||
*
|
|
||||||
* <p>This applies to the majority of the endpoints.
|
|
||||||
*/
|
*/
|
||||||
AUTH_API_ADMIN(ImmutableList.of(AuthMethod.API), AuthLevel.APP, UserPolicy.ADMIN);
|
AUTH_API_ADMIN(ImmutableList.of(AuthMethod.API), AuthLevel.APP, UserPolicy.ADMIN);
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ package google.registry.request.auth;
|
||||||
|
|
||||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
|
||||||
import com.google.appengine.api.oauth.OAuthService;
|
|
||||||
import com.google.appengine.api.oauth.OAuthServiceFactory;
|
|
||||||
import com.google.auth.oauth2.TokenVerifier;
|
import com.google.auth.oauth2.TokenVerifier;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
@ -36,9 +34,6 @@ public class AuthModule {
|
||||||
// IAP-signed JWT will be in this header.
|
// IAP-signed JWT will be in this header.
|
||||||
// See https://cloud.google.com/iap/docs/signed-headers-howto#securing_iap_headers.
|
// See https://cloud.google.com/iap/docs/signed-headers-howto#securing_iap_headers.
|
||||||
public static final String IAP_HEADER_NAME = "X-Goog-IAP-JWT-Assertion";
|
public static final String IAP_HEADER_NAME = "X-Goog-IAP-JWT-Assertion";
|
||||||
// GAE will put the content in header "proxy-authorization" in this header when it routes the
|
|
||||||
// request to the app.
|
|
||||||
public static final String PROXY_HEADER_NAME = "X-Google-Proxy-Authorization";
|
|
||||||
public static final String BEARER_PREFIX = "Bearer ";
|
public static final String BEARER_PREFIX = "Bearer ";
|
||||||
// TODO: Change the IAP audience format once we are on GKE.
|
// TODO: Change the IAP audience format once we are on GKE.
|
||||||
// See: https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
|
// See: https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
|
||||||
|
@ -46,16 +41,12 @@ public class AuthModule {
|
||||||
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
|
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
|
||||||
private static final String REGULAR_ISSUER_URL = "https://accounts.google.com";
|
private static final String REGULAR_ISSUER_URL = "https://accounts.google.com";
|
||||||
|
|
||||||
/** Provides the custom authentication mechanisms (including OAuth and OIDC). */
|
/** Provides the custom authentication mechanisms. */
|
||||||
@Provides
|
@Provides
|
||||||
ImmutableList<AuthenticationMechanism> provideApiAuthenticationMechanisms(
|
ImmutableList<AuthenticationMechanism> provideApiAuthenticationMechanisms(
|
||||||
OAuthAuthenticationMechanism oauthAuthenticationMechanism,
|
|
||||||
IapOidcAuthenticationMechanism iapOidcAuthenticationMechanism,
|
IapOidcAuthenticationMechanism iapOidcAuthenticationMechanism,
|
||||||
RegularOidcAuthenticationMechanism regularOidcAuthenticationMechanism) {
|
RegularOidcAuthenticationMechanism regularOidcAuthenticationMechanism) {
|
||||||
return ImmutableList.of(
|
return ImmutableList.of(iapOidcAuthenticationMechanism, regularOidcAuthenticationMechanism);
|
||||||
oauthAuthenticationMechanism,
|
|
||||||
iapOidcAuthenticationMechanism,
|
|
||||||
regularOidcAuthenticationMechanism);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
|
@ -64,12 +55,6 @@ public class AuthModule {
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@interface RegularOidc {}
|
@interface RegularOidc {}
|
||||||
|
|
||||||
/** Provides the OAuthService instance. */
|
|
||||||
@Provides
|
|
||||||
OAuthService provideOauthService() {
|
|
||||||
return OAuthServiceFactory.getOAuthService();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@IapOidc
|
@IapOidc
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -98,11 +83,7 @@ public class AuthModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
TokenExtractor provideRegularTokenExtractor() {
|
TokenExtractor provideRegularTokenExtractor() {
|
||||||
return request -> {
|
return request -> {
|
||||||
// TODO: only check the Authorizaiton header after the migration to OIDC is complete.
|
String rawToken = request.getHeader(AUTHORIZATION);
|
||||||
String rawToken = request.getHeader(PROXY_HEADER_NAME);
|
|
||||||
if (rawToken == null) {
|
|
||||||
rawToken = request.getHeader(AUTHORIZATION);
|
|
||||||
}
|
|
||||||
if (rawToken != null && rawToken.startsWith(BEARER_PREFIX)) {
|
if (rawToken != null && rawToken.startsWith(BEARER_PREFIX)) {
|
||||||
return rawToken.substring(BEARER_PREFIX.length());
|
return rawToken.substring(BEARER_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
package google.registry.request.auth;
|
package google.registry.request.auth;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthLevel.APP;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthLevel.USER;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||||
|
@ -22,8 +24,8 @@ import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Results of authentication for a given HTTP request, as emitted by an
|
* Results of authentication for a given HTTP request, as emitted by an {@link
|
||||||
* {@link AuthenticationMechanism}.
|
* AuthenticationMechanism}.
|
||||||
*/
|
*/
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract class AuthResult {
|
public abstract class AuthResult {
|
||||||
|
@ -33,6 +35,10 @@ public abstract class AuthResult {
|
||||||
/** Information about the authenticated user, if there is one. */
|
/** Information about the authenticated user, if there is one. */
|
||||||
public abstract Optional<UserAuthInfo> userAuthInfo();
|
public abstract Optional<UserAuthInfo> userAuthInfo();
|
||||||
|
|
||||||
|
/** Service account email of the authenticated app, if there is one. */
|
||||||
|
@SuppressWarnings("unused") // The service account will be logged upon successful login.
|
||||||
|
public abstract Optional<String> appServiceAccount();
|
||||||
|
|
||||||
public boolean isAuthenticated() {
|
public boolean isAuthenticated() {
|
||||||
return authLevel() != AuthLevel.NONE;
|
return authLevel() != AuthLevel.NONE;
|
||||||
}
|
}
|
||||||
|
@ -47,15 +53,27 @@ public abstract class AuthResult {
|
||||||
.orElse("<logged-out user>");
|
.orElse("<logged-out user>");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthResult create(AuthLevel authLevel) {
|
public static AuthResult createApp(String email) {
|
||||||
return new AutoValue_AuthResult(authLevel, Optional.empty());
|
return create(APP, null, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthResult create(AuthLevel authLevel, @Nullable UserAuthInfo userAuthInfo) {
|
public static AuthResult createUser(UserAuthInfo userAuthInfo) {
|
||||||
if (authLevel == AuthLevel.USER) {
|
return create(USER, userAuthInfo, null);
|
||||||
checkNotNull(userAuthInfo);
|
}
|
||||||
}
|
|
||||||
return new AutoValue_AuthResult(authLevel, Optional.ofNullable(userAuthInfo));
|
private static AuthResult create(
|
||||||
|
AuthLevel authLevel, @Nullable UserAuthInfo userAuthInfo, @Nullable String email) {
|
||||||
|
checkArgument(
|
||||||
|
userAuthInfo == null || email == null,
|
||||||
|
"User auth info and service account email cannot be specificed at the same time");
|
||||||
|
checkArgument(
|
||||||
|
authLevel != USER || userAuthInfo != null,
|
||||||
|
"User auth info must be specified for auth level USER");
|
||||||
|
checkArgument(
|
||||||
|
authLevel != APP || email != null,
|
||||||
|
"Service account email must be specified for auth level APP");
|
||||||
|
return new AutoValue_AuthResult(
|
||||||
|
authLevel, Optional.ofNullable(userAuthInfo), Optional.ofNullable(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,5 +85,5 @@ public abstract class AuthResult {
|
||||||
* returns NOT_AUTHENTICATED in this case, as opposed to absent() if authentication failed and was
|
* returns NOT_AUTHENTICATED in this case, as opposed to absent() if authentication failed and was
|
||||||
* required. So as a return from an authorization check, this can be treated as a success.
|
* required. So as a return from an authorization check, this can be treated as a success.
|
||||||
*/
|
*/
|
||||||
public static final AuthResult NOT_AUTHENTICATED = create(AuthLevel.NONE);
|
public static final AuthResult NOT_AUTHENTICATED = create(AuthLevel.NONE, null, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.request.auth;
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.errorprone.annotations.Immutable;
|
import com.google.errorprone.annotations.Immutable;
|
||||||
|
import google.registry.model.console.UserRoles;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters used to configure the authenticator.
|
* Parameters used to configure the authenticator.
|
||||||
|
@ -42,7 +43,10 @@ public abstract class AuthSettings {
|
||||||
/** Available methods for authentication. */
|
/** Available methods for authentication. */
|
||||||
public enum AuthMethod {
|
public enum AuthMethod {
|
||||||
|
|
||||||
/** Authentication methods suitable for API-style access, such as OAuth 2. */
|
/**
|
||||||
|
* Authentication methods suitable for API-style access, such as {@link
|
||||||
|
* OidcTokenAuthenticationMechanism}.
|
||||||
|
*/
|
||||||
API,
|
API,
|
||||||
|
|
||||||
/** Legacy authentication using cookie-based App Engine Users API. Must come last if present. */
|
/** Legacy authentication using cookie-based App Engine Users API. Must come last if present. */
|
||||||
|
@ -68,10 +72,11 @@ public abstract class AuthSettings {
|
||||||
/**
|
/**
|
||||||
* Authentication required, but user not required.
|
* Authentication required, but user not required.
|
||||||
*
|
*
|
||||||
* <p>In Auth: Authentication is required, but app-internal authentication (which isn't
|
* <p>In Auth: authentication is required, but App-internal authentication (which isn't
|
||||||
* associated with a specific user) is permitted.
|
* associated with a specific user, but a service account) is permitted. Examples include
|
||||||
|
* requests from Cloud Tasks, Cloud Scheduler, and the proxy.
|
||||||
*
|
*
|
||||||
* <p>In AuthResult: App-internal authentication was successful.
|
* <p>In AuthResult: App-internal authentication (via service accounts) was successful.
|
||||||
*/
|
*/
|
||||||
APP,
|
APP,
|
||||||
|
|
||||||
|
@ -93,10 +98,14 @@ public abstract class AuthSettings {
|
||||||
PUBLIC,
|
PUBLIC,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is a user, it must be an admin, as determined by isUserAdmin().
|
* If there is a user, it must be an admin, as determined by {@link UserAuthInfo#isUserAdmin()}.
|
||||||
*
|
*
|
||||||
* <p>Note that, according to App Engine, anybody with access to the app in the GCP Console,
|
* <p>Note that, if the user returned is an App Engine {@link
|
||||||
|
* com.google.appengine.api.users.User} , anybody with access to the app in the GCP Console,
|
||||||
* including editors and viewers, is an admin.
|
* including editors and viewers, is an admin.
|
||||||
|
*
|
||||||
|
* <p>On the other hand, if the user is a {@link google.registry.model.console.User}, the admin
|
||||||
|
* role is explicitly defined in that object via the {@link UserRoles#isAdmin()} method.
|
||||||
*/
|
*/
|
||||||
ADMIN
|
ADMIN
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
/**
|
/**
|
||||||
* A particular way to authenticate an HTTP request, returning an {@link AuthResult}.
|
* A particular way to authenticate an HTTP request, returning an {@link AuthResult}.
|
||||||
*
|
*
|
||||||
* <p>For instance, a request could be authenticated using OAuth, via special request headers, etc.
|
* <p>For instance, a request could be authenticated using OIDC, via special request headers, etc.
|
||||||
*/
|
*/
|
||||||
public interface AuthenticationMechanism {
|
public interface AuthenticationMechanism {
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,7 @@ package google.registry.request.auth;
|
||||||
|
|
||||||
import static com.google.common.base.Strings.emptyToNull;
|
import static com.google.common.base.Strings.emptyToNull;
|
||||||
import static com.google.common.base.Strings.nullToEmpty;
|
import static com.google.common.base.Strings.nullToEmpty;
|
||||||
import static google.registry.request.auth.AuthSettings.AuthLevel.NONE;
|
import static google.registry.request.auth.AuthResult.NOT_AUTHENTICATED;
|
||||||
import static google.registry.request.auth.AuthSettings.AuthLevel.USER;
|
|
||||||
import static google.registry.security.XsrfTokenManager.P_CSRF_TOKEN;
|
import static google.registry.security.XsrfTokenManager.P_CSRF_TOKEN;
|
||||||
import static google.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
import static google.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
||||||
|
|
||||||
|
@ -49,15 +48,14 @@ public class LegacyAuthenticationMechanism implements AuthenticationMechanism {
|
||||||
@Override
|
@Override
|
||||||
public AuthResult authenticate(HttpServletRequest request) {
|
public AuthResult authenticate(HttpServletRequest request) {
|
||||||
if (!userService.isUserLoggedIn()) {
|
if (!userService.isUserLoggedIn()) {
|
||||||
return AuthResult.create(NONE);
|
return NOT_AUTHENTICATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SAFE_METHODS.contains(request.getMethod()) && !validateXsrf(request)) {
|
if (!SAFE_METHODS.contains(request.getMethod()) && !validateXsrf(request)) {
|
||||||
return AuthResult.create(NONE);
|
return NOT_AUTHENTICATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AuthResult.create(
|
return AuthResult.createUser(
|
||||||
USER,
|
|
||||||
UserAuthInfo.create(userService.getCurrentUser(), userService.isUserAdmin()));
|
UserAuthInfo.create(userService.getCurrentUser(), userService.isUserAdmin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
// Copyright 2017 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 google.registry.request.auth.AuthModule.BEARER_PREFIX;
|
|
||||||
import static google.registry.request.auth.AuthSettings.AuthLevel.NONE;
|
|
||||||
import static google.registry.request.auth.AuthSettings.AuthLevel.USER;
|
|
||||||
|
|
||||||
import com.google.appengine.api.oauth.OAuthRequestException;
|
|
||||||
import com.google.appengine.api.oauth.OAuthService;
|
|
||||||
import com.google.appengine.api.oauth.OAuthServiceFailureException;
|
|
||||||
import com.google.appengine.api.users.User;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
import google.registry.config.RegistryConfig.Config;
|
|
||||||
import google.registry.config.RegistryEnvironment;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OAuth authentication mechanism, using the OAuthService interface.
|
|
||||||
*
|
|
||||||
* <p>Only OAuth version 2 is supported.
|
|
||||||
*/
|
|
||||||
public class OAuthAuthenticationMechanism implements AuthenticationMechanism {
|
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
private final OAuthService oauthService;
|
|
||||||
|
|
||||||
/** The available OAuth scopes for which {@link OAuthService} should check. */
|
|
||||||
private final ImmutableSet<String> availableOauthScopes;
|
|
||||||
|
|
||||||
/** The OAuth scopes which must all be present for authentication to succeed. */
|
|
||||||
private final ImmutableSet<String> requiredOauthScopes;
|
|
||||||
|
|
||||||
private final ImmutableSet<String> allowedOauthClientIds;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public OAuthAuthenticationMechanism(
|
|
||||||
OAuthService oauthService,
|
|
||||||
@Config("availableOauthScopes") ImmutableSet<String> availableOauthScopes,
|
|
||||||
@Config("requiredOauthScopes") ImmutableSet<String> requiredOauthScopes,
|
|
||||||
@Config("allowedOauthClientIds") ImmutableSet<String> allowedOauthClientIds) {
|
|
||||||
this.oauthService = oauthService;
|
|
||||||
this.availableOauthScopes = availableOauthScopes;
|
|
||||||
this.requiredOauthScopes = requiredOauthScopes;
|
|
||||||
this.allowedOauthClientIds = allowedOauthClientIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthResult authenticate(HttpServletRequest request) {
|
|
||||||
|
|
||||||
// Make sure that there is an Authorization header in Bearer form. OAuthService also accepts
|
|
||||||
// tokens in the request body and URL string, but we should not use those, since they are more
|
|
||||||
// likely to be logged than the Authorization header. Checking to make sure there's a token also
|
|
||||||
// avoids unnecessary RPCs, since OAuthService itself does not check whether the header is
|
|
||||||
// present. In theory, there could be more than one Authorization header, but we only check the
|
|
||||||
// first one, because there's not a legitimate use case for having more than one, and
|
|
||||||
// OAuthService itself only looks at the first one anyway.
|
|
||||||
String header = request.getHeader(AUTHORIZATION);
|
|
||||||
if ((header == null) || !header.startsWith(BEARER_PREFIX)) {
|
|
||||||
if (header != null) {
|
|
||||||
logger.atInfo().log("Invalid authorization header.");
|
|
||||||
}
|
|
||||||
return AuthResult.create(NONE);
|
|
||||||
}
|
|
||||||
// Assume that, if a bearer token is found, it's what OAuthService will use to attempt
|
|
||||||
// authentication. This is not technically guaranteed by the contract of OAuthService; see
|
|
||||||
// OAuthTokenInfo for more information.
|
|
||||||
String rawAccessToken =
|
|
||||||
RegistryEnvironment.get() == RegistryEnvironment.PRODUCTION
|
|
||||||
? "Raw token redacted in prod"
|
|
||||||
: header.substring(BEARER_PREFIX.length());
|
|
||||||
|
|
||||||
// Get the OAuth information. The various oauthService method calls use a single cached
|
|
||||||
// authentication result, so we can call them one by one.
|
|
||||||
User currentUser;
|
|
||||||
boolean isUserAdmin;
|
|
||||||
String oauthClientId;
|
|
||||||
ImmutableSet<String> authorizedScopes;
|
|
||||||
try {
|
|
||||||
String[] availableOauthScopeArray = availableOauthScopes.toArray(new String[0]);
|
|
||||||
currentUser = oauthService.getCurrentUser(availableOauthScopeArray);
|
|
||||||
isUserAdmin = oauthService.isUserAdmin(availableOauthScopeArray);
|
|
||||||
logger.atInfo().log(
|
|
||||||
"Current user: %s (%s).", currentUser, isUserAdmin ? "admin" : "not admin");
|
|
||||||
oauthClientId = oauthService.getClientId(availableOauthScopeArray);
|
|
||||||
logger.atInfo().log("OAuth client ID: %s", oauthClientId);
|
|
||||||
authorizedScopes =
|
|
||||||
ImmutableSet.copyOf(oauthService.getAuthorizedScopes(availableOauthScopeArray));
|
|
||||||
logger.atInfo().log("Authorized scope(s): %s", authorizedScopes);
|
|
||||||
} catch (OAuthRequestException | OAuthServiceFailureException e) {
|
|
||||||
logger.atInfo().withCause(e).log("Unable to get OAuth information.");
|
|
||||||
return AuthResult.create(NONE);
|
|
||||||
}
|
|
||||||
if ((currentUser == null) || (oauthClientId == null) || (authorizedScopes == null)) {
|
|
||||||
return AuthResult.create(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that the client ID matches, to avoid a confused deputy attack; see:
|
|
||||||
// http://stackoverflow.com/a/17439317/1179226
|
|
||||||
if (!allowedOauthClientIds.contains(oauthClientId)) {
|
|
||||||
logger.atInfo().log("OAuth client ID is not allowed.");
|
|
||||||
return AuthResult.create(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that all required scopes are present.
|
|
||||||
if (!authorizedScopes.containsAll(requiredOauthScopes)) {
|
|
||||||
logger.atInfo().log("Missing required scope(s).");
|
|
||||||
return AuthResult.create(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the {@link AuthResult}, including the OAuth token info.
|
|
||||||
return AuthResult.create(
|
|
||||||
USER,
|
|
||||||
UserAuthInfo.create(
|
|
||||||
currentUser,
|
|
||||||
isUserAdmin,
|
|
||||||
OAuthTokenInfo.create(
|
|
||||||
ImmutableSet.copyOf(authorizedScopes), oauthClientId, rawAccessToken)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright 2017 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 com.google.auto.value.AutoValue;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
/** Information provided by the OAuth authentication mechanism (only) about the session. */
|
|
||||||
@AutoValue
|
|
||||||
public abstract class OAuthTokenInfo {
|
|
||||||
|
|
||||||
/** Authorized OAuth scopes granted by the access token provided with the request. */
|
|
||||||
abstract ImmutableSet<String> authorizedScopes();
|
|
||||||
|
|
||||||
/** OAuth client ID from the access token provided with the request. */
|
|
||||||
abstract String oauthClientId();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raw OAuth access token value provided with the request, for passing along to downstream APIs as
|
|
||||||
* appropriate.
|
|
||||||
*
|
|
||||||
* <p>Note that the request parsing code makes certain assumptions about whether the Authorization
|
|
||||||
* header was used as the source of the token. Because OAuthService could theoretically fall back
|
|
||||||
* to some other source of authentication, it might be possible for rawAccessToken not to have
|
|
||||||
* been the source of OAuth authentication. Looking at the code of OAuthService, that could not
|
|
||||||
* currently happen, but if OAuthService were modified in the future so that it tried the bearer
|
|
||||||
* token, and then when that failed, fell back to another, successful authentication path, then
|
|
||||||
* rawAccessToken might not be valid.
|
|
||||||
*/
|
|
||||||
abstract String rawAccessToken();
|
|
||||||
|
|
||||||
static OAuthTokenInfo create(
|
|
||||||
ImmutableSet<String> authorizedScopes, String oauthClientId, String rawAccessToken) {
|
|
||||||
return new AutoValue_OAuthTokenInfo(authorizedScopes, oauthClientId, rawAccessToken);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
package google.registry.request.auth;
|
package google.registry.request.auth;
|
||||||
|
|
||||||
import static google.registry.request.auth.AuthSettings.AuthLevel.APP;
|
|
||||||
|
|
||||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||||
import com.google.auth.oauth2.TokenVerifier;
|
import com.google.auth.oauth2.TokenVerifier;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -97,12 +95,11 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||||
}
|
}
|
||||||
Optional<User> maybeUser = UserDao.loadUser(email);
|
Optional<User> maybeUser = UserDao.loadUser(email);
|
||||||
if (maybeUser.isPresent()) {
|
if (maybeUser.isPresent()) {
|
||||||
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(maybeUser.get()));
|
return AuthResult.createUser(UserAuthInfo.create(maybeUser.get()));
|
||||||
}
|
}
|
||||||
// TODO: implement caching so we don't have to look up the database for every request.
|
|
||||||
logger.atInfo().log("No end user found for email address %s", email);
|
logger.atInfo().log("No end user found for email address %s", email);
|
||||||
if (serviceAccountEmails.stream().anyMatch(e -> e.equals(email))) {
|
if (serviceAccountEmails.stream().anyMatch(e -> e.equals(email))) {
|
||||||
return AuthResult.create(APP);
|
return AuthResult.createApp(email);
|
||||||
}
|
}
|
||||||
logger.atInfo().log("No service account found for email address %s", email);
|
logger.atInfo().log("No service account found for email address %s", email);
|
||||||
logger.atWarning().log(
|
logger.atWarning().log(
|
||||||
|
@ -153,15 +150,8 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||||
*
|
*
|
||||||
* <p>If the endpoint is not behind IAP, we can try to authenticate the OIDC token supplied in the
|
* <p>If the endpoint is not behind IAP, we can try to authenticate the OIDC token supplied in the
|
||||||
* request header directly. Ideally we would like all endpoints to be behind IAP, but being able
|
* request header directly. Ideally we would like all endpoints to be behind IAP, but being able
|
||||||
* to authenticate the token directly provides us with the flexibility to do away with OAuth-based
|
* to authenticate the token directly provides us with some extra flexibility that comes in handy,
|
||||||
* {@link OAuthAuthenticationMechanism} that is tied to App Engine runtime without having to turn
|
* at least during the migration to GKE.
|
||||||
* on IAP, which is an all-or-nothing switch for each GAE service (i.e. no way to turn it on only
|
|
||||||
* for certain GAE endpoints).
|
|
||||||
*
|
|
||||||
* <p>Note that this mechanism will try to first extract the token under the "proxy-authorization"
|
|
||||||
* header, before trying "authorization". This is because currently the GAE OAuth service always
|
|
||||||
* uses "authorization", and we would like to provide a way for both auth mechanisms to be working
|
|
||||||
* at the same time for the same request.
|
|
||||||
*
|
*
|
||||||
* @see <a href=https://datatracker.ietf.org/doc/html/rfc6750>Bearer Token Usage</a>
|
* @see <a href=https://datatracker.ietf.org/doc/html/rfc6750>Bearer Token Usage</a>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -60,7 +60,8 @@ public class RequestAuthenticator {
|
||||||
if (auth.minimumLevel() == APP && !authResult.isAuthenticated()) {
|
if (auth.minimumLevel() == APP && !authResult.isAuthenticated()) {
|
||||||
logger.atWarning().log("Not authorized; no authentication found.");
|
logger.atWarning().log("Not authorized; no authentication found.");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else if (auth.minimumLevel() == USER && authResult.authLevel() != USER) {
|
}
|
||||||
|
if (auth.minimumLevel() == USER && authResult.authLevel() != USER) {
|
||||||
logger.atWarning().log("Not authorized; no authenticated user.");
|
logger.atWarning().log("Not authorized; no authenticated user.");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -81,12 +82,12 @@ public class RequestAuthenticator {
|
||||||
* @param req the {@link HttpServletRequest}; some authentication mechanisms use HTTP headers
|
* @param req the {@link HttpServletRequest}; some authentication mechanisms use HTTP headers
|
||||||
* @return an authentication result; if no authentication was made, returns NOT_AUTHENTICATED
|
* @return an authentication result; if no authentication was made, returns NOT_AUTHENTICATED
|
||||||
*/
|
*/
|
||||||
private AuthResult authenticate(AuthSettings auth, HttpServletRequest req) {
|
AuthResult authenticate(AuthSettings auth, HttpServletRequest req) {
|
||||||
checkAuthConfig(auth);
|
checkAuthConfig(auth);
|
||||||
for (AuthMethod authMethod : auth.methods()) {
|
for (AuthMethod authMethod : auth.methods()) {
|
||||||
AuthResult authResult;
|
AuthResult authResult;
|
||||||
switch (authMethod) {
|
switch (authMethod) {
|
||||||
// API-based user authentication mechanisms, such as OAuth and OIDC.
|
// API-based user authentication mechanisms, such as OIDC.
|
||||||
case API:
|
case API:
|
||||||
for (AuthenticationMechanism authMechanism : apiAuthenticationMechanisms) {
|
for (AuthenticationMechanism authMechanism : apiAuthenticationMechanisms) {
|
||||||
authResult = authMechanism.authenticate(req);
|
authResult = authMechanism.authenticate(req);
|
||||||
|
@ -113,10 +114,9 @@ public class RequestAuthenticator {
|
||||||
|
|
||||||
/** Validates an AuthSettings object, checking for invalid setting combinations. */
|
/** Validates an AuthSettings object, checking for invalid setting combinations. */
|
||||||
static void checkAuthConfig(AuthSettings auth) {
|
static void checkAuthConfig(AuthSettings auth) {
|
||||||
ImmutableList<AuthMethod> authMethods = ImmutableList.copyOf(auth.methods());
|
checkArgument(!auth.methods().isEmpty(), "Must specify at least one auth method");
|
||||||
checkArgument(!authMethods.isEmpty(), "Must specify at least one auth method");
|
|
||||||
checkArgument(
|
checkArgument(
|
||||||
Ordering.explicit(AuthMethod.API, AuthMethod.LEGACY).isStrictlyOrdered(authMethods),
|
Ordering.explicit(AuthMethod.API, AuthMethod.LEGACY).isStrictlyOrdered(auth.methods()),
|
||||||
"Auth methods must be unique and strictly in order - API, LEGACY");
|
"Auth methods must be unique and strictly in order - API, LEGACY");
|
||||||
checkArgument(
|
checkArgument(
|
||||||
(auth.minimumLevel() != NONE) || (auth.userPolicy() != ADMIN),
|
(auth.minimumLevel() != NONE) || (auth.userPolicy() != ADMIN),
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.util.Optional;
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract class UserAuthInfo {
|
public abstract class UserAuthInfo {
|
||||||
|
|
||||||
|
public abstract Optional<google.registry.model.console.User> consoleUser();
|
||||||
|
|
||||||
/** User object from the AppEngine Users API. */
|
/** User object from the AppEngine Users API. */
|
||||||
public abstract Optional<User> appEngineUser();
|
public abstract Optional<User> appEngineUser();
|
||||||
|
|
||||||
|
@ -34,11 +36,6 @@ public abstract class UserAuthInfo {
|
||||||
*/
|
*/
|
||||||
public abstract boolean isUserAdmin();
|
public abstract boolean isUserAdmin();
|
||||||
|
|
||||||
public abstract Optional<google.registry.model.console.User> consoleUser();
|
|
||||||
|
|
||||||
/** Used by the OAuth authentication mechanism (only) to return information about the session. */
|
|
||||||
public abstract Optional<OAuthTokenInfo> oauthTokenInfo();
|
|
||||||
|
|
||||||
public String getEmailAddress() {
|
public String getEmailAddress() {
|
||||||
return appEngineUser()
|
return appEngineUser()
|
||||||
.map(User::getEmail)
|
.map(User::getEmail)
|
||||||
|
@ -51,20 +48,12 @@ public abstract class UserAuthInfo {
|
||||||
.orElseGet(() -> consoleUser().get().getEmailAddress());
|
.orElseGet(() -> consoleUser().get().getEmailAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserAuthInfo create(
|
public static UserAuthInfo create(User user, boolean isUserAdmin) {
|
||||||
User user, boolean isUserAdmin) {
|
return new AutoValue_UserAuthInfo(Optional.empty(), Optional.of(user), isUserAdmin);
|
||||||
return new AutoValue_UserAuthInfo(
|
|
||||||
Optional.of(user), isUserAdmin, Optional.empty(), Optional.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserAuthInfo create(
|
|
||||||
User user, boolean isUserAdmin, OAuthTokenInfo oauthTokenInfo) {
|
|
||||||
return new AutoValue_UserAuthInfo(
|
|
||||||
Optional.of(user), isUserAdmin, Optional.empty(), Optional.of(oauthTokenInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserAuthInfo create(google.registry.model.console.User user) {
|
public static UserAuthInfo create(google.registry.model.console.User user) {
|
||||||
return new AutoValue_UserAuthInfo(
|
return new AutoValue_UserAuthInfo(
|
||||||
Optional.empty(), user.getUserRoles().isAdmin(), Optional.of(user), Optional.empty());
|
Optional.of(user), Optional.empty(), user.getUserRoles().isAdmin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,13 +50,6 @@ final class RegistryCli implements CommandRunner {
|
||||||
description = "Sets the default environment to run the command.")
|
description = "Sets the default environment to run the command.")
|
||||||
private RegistryToolEnvironment environment = RegistryToolEnvironment.PRODUCTION;
|
private RegistryToolEnvironment environment = RegistryToolEnvironment.PRODUCTION;
|
||||||
|
|
||||||
@Parameter(
|
|
||||||
names = "--oauth",
|
|
||||||
description =
|
|
||||||
"Turn on OAuth-based authentication, the usage of which is to be deprecated. Use"
|
|
||||||
+ " `create_user` to create an Admin user that allows for OIDC-based authentication.")
|
|
||||||
private boolean oAuth = false;
|
|
||||||
|
|
||||||
@Parameter(
|
@Parameter(
|
||||||
names = {"-c", "--commands"},
|
names = {"-c", "--commands"},
|
||||||
description = "Returns all command names.")
|
description = "Returns all command names.")
|
||||||
|
@ -168,7 +161,6 @@ final class RegistryCli implements CommandRunner {
|
||||||
DaggerRegistryToolComponent.builder()
|
DaggerRegistryToolComponent.builder()
|
||||||
.credentialFilePath(credentialJson)
|
.credentialFilePath(credentialJson)
|
||||||
.sqlAccessInfoFile(sqlAccessInfoFile)
|
.sqlAccessInfoFile(sqlAccessInfoFile)
|
||||||
.addOAuthHeader(oAuth)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// JCommander stores sub-commands as nested JCommander objects containing a list of user objects
|
// JCommander stores sub-commands as nested JCommander objects containing a list of user objects
|
||||||
|
|
|
@ -191,9 +191,6 @@ interface RegistryToolComponent {
|
||||||
@BindsInstance
|
@BindsInstance
|
||||||
Builder sqlAccessInfoFile(@Nullable @Config("sqlAccessInfoFile") String sqlAccessInfoFile);
|
Builder sqlAccessInfoFile(@Nullable @Config("sqlAccessInfoFile") String sqlAccessInfoFile);
|
||||||
|
|
||||||
@BindsInstance
|
|
||||||
Builder addOAuthHeader(@Config("addOauthHeader") boolean addOauthHeader);
|
|
||||||
|
|
||||||
RegistryToolComponent build();
|
RegistryToolComponent build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.net.HttpHeaders.PROXY_AUTHORIZATION;
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
|
||||||
import com.google.api.client.http.HttpRequestFactory;
|
import com.google.api.client.http.HttpRequestFactory;
|
||||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||||
|
@ -42,8 +42,7 @@ final class RequestFactoryModule {
|
||||||
@Provides
|
@Provides
|
||||||
static HttpRequestFactory provideHttpRequestFactory(
|
static HttpRequestFactory provideHttpRequestFactory(
|
||||||
@ApplicationDefaultCredential GoogleCredentialsBundle credentialsBundle,
|
@ApplicationDefaultCredential GoogleCredentialsBundle credentialsBundle,
|
||||||
@Config("oauthClientId") String oauthClientId,
|
@Config("oauthClientId") String oauthClientId) {
|
||||||
@Config("addOauthHeader") boolean addOauthHeader) {
|
|
||||||
if (RegistryConfig.areServersLocal()) {
|
if (RegistryConfig.areServersLocal()) {
|
||||||
return new NetHttpTransport()
|
return new NetHttpTransport()
|
||||||
.createRequestFactory(
|
.createRequestFactory(
|
||||||
|
@ -55,15 +54,11 @@ final class RequestFactoryModule {
|
||||||
return new NetHttpTransport()
|
return new NetHttpTransport()
|
||||||
.createRequestFactory(
|
.createRequestFactory(
|
||||||
request -> {
|
request -> {
|
||||||
if (addOauthHeader) {
|
// Set OIDC token as the bearer token.
|
||||||
// Use the standard credential initializer to set the Authorization header
|
|
||||||
credentialsBundle.getHttpRequestInitializer().initialize(request);
|
|
||||||
}
|
|
||||||
// Set OIDC token as the alternative bearer token.
|
|
||||||
request
|
request
|
||||||
.getHeaders()
|
.getHeaders()
|
||||||
.set(
|
.set(
|
||||||
PROXY_AUTHORIZATION,
|
AUTHORIZATION,
|
||||||
"Bearer "
|
"Bearer "
|
||||||
+ OidcTokenUtils.createOidcToken(credentialsBundle, oauthClientId));
|
+ OidcTokenUtils.createOidcToken(credentialsBundle, oauthClientId));
|
||||||
// GAE request times out after 10 min, so here we set the timeout to 10 min. This is
|
// GAE request times out after 10 min, so here we set the timeout to 10 min. This is
|
||||||
|
|
|
@ -51,7 +51,7 @@ import org.joda.time.DateTime;
|
||||||
service = Action.Service.PUBAPI,
|
service = Action.Service.PUBAPI,
|
||||||
path = "/_dr/whois",
|
path = "/_dr/whois",
|
||||||
method = POST,
|
method = POST,
|
||||||
auth = Auth.AUTH_API_PUBLIC)
|
auth = Auth.AUTH_API_ADMIN)
|
||||||
public class WhoisAction implements Runnable {
|
public class WhoisAction implements Runnable {
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
|
@ -28,7 +28,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.Actions;
|
import google.registry.request.Actions;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
|
@ -48,13 +47,11 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
|
||||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||||
|
|
||||||
protected static final AuthResult AUTH_RESULT =
|
protected static final AuthResult AUTH_RESULT =
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(new User("rdap.user@user.com", "gmail.com", "12345"), false));
|
UserAuthInfo.create(new User("rdap.user@user.com", "gmail.com", "12345"), false));
|
||||||
|
|
||||||
protected static final AuthResult AUTH_RESULT_ADMIN =
|
protected static final AuthResult AUTH_RESULT_ADMIN =
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(new User("rdap.admin@google.com", "gmail.com", "12345"), true));
|
UserAuthInfo.create(new User("rdap.admin@google.com", "gmail.com", "12345"), true));
|
||||||
|
|
||||||
protected FakeResponse response = new FakeResponse();
|
protected FakeResponse response = new FakeResponse();
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static google.registry.request.Action.Method.GET;
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
import static google.registry.request.auth.Auth.AUTH_API_ADMIN;
|
import static google.registry.request.auth.Auth.AUTH_API_ADMIN;
|
||||||
import static google.registry.request.auth.Auth.AUTH_PUBLIC;
|
import static google.registry.request.auth.Auth.AUTH_PUBLIC;
|
||||||
|
import static google.registry.request.auth.AuthResult.NOT_AUTHENTICATED;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -228,7 +229,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/bumblebee");
|
when(req.getRequestURI()).thenReturn("/bumblebee");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
when(req.getRequestURI()).thenReturn("/bumblebee");
|
when(req.getRequestURI()).thenReturn("/bumblebee");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -255,7 +256,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/bumblebee/hive");
|
when(req.getRequestURI()).thenReturn("/bumblebee/hive");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -268,7 +269,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
when(req.getRequestURI()).thenReturn("/sloth");
|
when(req.getRequestURI()).thenReturn("/sloth");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -284,7 +285,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
when(req.getRequestURI()).thenReturn("/sloth/nest");
|
when(req.getRequestURI()).thenReturn("/sloth/nest");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -296,7 +297,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/fail");
|
when(req.getRequestURI()).thenReturn("/fail");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -311,7 +312,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/failAtConstruction");
|
when(req.getRequestURI()).thenReturn("/failAtConstruction");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -324,7 +325,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/bogus");
|
when(req.getRequestURI()).thenReturn("/bogus");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -336,7 +337,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
when(req.getRequestURI()).thenReturn("/fail");
|
when(req.getRequestURI()).thenReturn("/fail");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -348,7 +349,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("FIREAWAY");
|
when(req.getMethod()).thenReturn("FIREAWAY");
|
||||||
when(req.getRequestURI()).thenReturn("/fail");
|
when(req.getRequestURI()).thenReturn("/fail");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -364,7 +365,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("get");
|
when(req.getMethod()).thenReturn("get");
|
||||||
when(req.getRequestURI()).thenReturn("/bumblebee");
|
when(req.getRequestURI()).thenReturn("/bumblebee");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -386,7 +387,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
when(req.getRequestURI()).thenReturn("/safe-sloth");
|
when(req.getRequestURI()).thenReturn("/safe-sloth");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -399,7 +400,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/safe-sloth");
|
when(req.getRequestURI()).thenReturn("/safe-sloth");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -412,7 +413,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/auth/none");
|
when(req.getRequestURI()).thenReturn("/auth/none");
|
||||||
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_PUBLIC.authSettings(), req))
|
||||||
.thenReturn(Optional.of(AuthResult.create(AuthLevel.NONE)));
|
.thenReturn(Optional.of(NOT_AUTHENTICATED));
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -440,8 +441,7 @@ public final class RequestHandlerTest {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getRequestURI()).thenReturn("/auth/adminUser");
|
when(req.getRequestURI()).thenReturn("/auth/adminUser");
|
||||||
when(requestAuthenticator.authorize(AUTH_API_ADMIN.authSettings(), req))
|
when(requestAuthenticator.authorize(AUTH_API_ADMIN.authSettings(), req))
|
||||||
.thenReturn(
|
.thenReturn(Optional.of(AuthResult.createUser(UserAuthInfo.create(testUser, true))));
|
||||||
Optional.of(AuthResult.create(AuthLevel.USER, UserAuthInfo.create(testUser, true))));
|
|
||||||
|
|
||||||
handler.handleRequest(req, rsp);
|
handler.handleRequest(req, rsp);
|
||||||
|
|
||||||
|
@ -449,7 +449,6 @@ public final class RequestHandlerTest {
|
||||||
assertThat(providedAuthResult.authLevel()).isEqualTo(AuthLevel.USER);
|
assertThat(providedAuthResult.authLevel()).isEqualTo(AuthLevel.USER);
|
||||||
assertThat(providedAuthResult.userAuthInfo()).isPresent();
|
assertThat(providedAuthResult.userAuthInfo()).isPresent();
|
||||||
assertThat(providedAuthResult.userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
assertThat(providedAuthResult.userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
||||||
assertThat(providedAuthResult.userAuthInfo().get().oauthTokenInfo()).isEmpty();
|
|
||||||
assertMetric("/auth/adminUser", GET, AuthLevel.USER, true);
|
assertMetric("/auth/adminUser", GET, AuthLevel.USER, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package google.registry.request.auth;
|
package google.registry.request.auth;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static google.registry.request.auth.AuthResult.NOT_AUTHENTICATED;
|
||||||
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
|
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
|
||||||
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
|
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
|
||||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||||
|
@ -40,7 +41,6 @@ import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.model.registrar.Registrar.State;
|
import google.registry.model.registrar.Registrar.State;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
||||||
import google.registry.util.JdkLoggerConfig;
|
import google.registry.util.JdkLoggerConfig;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -75,7 +75,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
|
|
||||||
private static final AuthResult USER = createAuthResult(false);
|
private static final AuthResult USER = createAuthResult(false);
|
||||||
private static final AuthResult GAE_ADMIN = createAuthResult(true);
|
private static final AuthResult GAE_ADMIN = createAuthResult(true);
|
||||||
private static final AuthResult NO_USER = AuthResult.create(AuthLevel.NONE);
|
private static final AuthResult NO_USER = NOT_AUTHENTICATED;
|
||||||
private static final Optional<String> SUPPORT_GROUP = Optional.of("support@registry.example");
|
private static final Optional<String> SUPPORT_GROUP = Optional.of("support@registry.example");
|
||||||
/** Registrar ID of a REAL registrar with a RegistrarContact for USER and GAE_ADMIN. */
|
/** Registrar ID of a REAL registrar with a RegistrarContact for USER and GAE_ADMIN. */
|
||||||
private static final String REGISTRAR_ID_WITH_CONTACT = "TheRegistrar";
|
private static final String REGISTRAR_ID_WITH_CONTACT = "TheRegistrar";
|
||||||
|
@ -94,8 +94,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
* @param isAdmin if true, the user is an administrator for the app-engine project.
|
* @param isAdmin if true, the user is an administrator for the app-engine project.
|
||||||
*/
|
*/
|
||||||
private static AuthResult createAuthResult(boolean isAdmin) {
|
private static AuthResult createAuthResult(boolean isAdmin) {
|
||||||
return AuthResult.create(
|
return AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(new User("johndoe@theregistrar.com", "theregistrar.com"), isAdmin));
|
UserAuthInfo.create(new User("johndoe@theregistrar.com", "theregistrar.com"), isAdmin));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,8 +294,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
void testGetRegistrarForUser_inContacts_isNotAdmin_caseInsensitive() throws Exception {
|
void testGetRegistrarForUser_inContacts_isNotAdmin_caseInsensitive() throws Exception {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
REGISTRAR_ID_WITH_CONTACT,
|
REGISTRAR_ID_WITH_CONTACT,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(new User("JohnDoe@theregistrar.com", "theregistrar.com"), false)),
|
UserAuthInfo.create(new User("JohnDoe@theregistrar.com", "theregistrar.com"), false)),
|
||||||
"user JohnDoe@theregistrar.com has [OWNER] access to registrar TheRegistrar");
|
"user JohnDoe@theregistrar.com has [OWNER] access to registrar TheRegistrar");
|
||||||
verify(lazyGroupsConnection).get();
|
verify(lazyGroupsConnection).get();
|
||||||
|
@ -421,7 +419,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
.setUserRoles(
|
.setUserRoles(
|
||||||
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
||||||
.build();
|
.build();
|
||||||
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
AuthResult authResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthenticatedRegistrarAccessor registrarAccessor =
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
new AuthenticatedRegistrarAccessor(
|
new AuthenticatedRegistrarAccessor(
|
||||||
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
||||||
|
@ -446,7 +444,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
.setEmailAddress("email@email.com")
|
.setEmailAddress("email@email.com")
|
||||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_AGENT).build())
|
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_AGENT).build())
|
||||||
.build();
|
.build();
|
||||||
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
AuthResult authResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthenticatedRegistrarAccessor registrarAccessor =
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
new AuthenticatedRegistrarAccessor(
|
new AuthenticatedRegistrarAccessor(
|
||||||
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
||||||
|
@ -471,7 +469,7 @@ class AuthenticatedRegistrarAccessorTest {
|
||||||
RegistrarRole.ACCOUNT_MANAGER))
|
RegistrarRole.ACCOUNT_MANAGER))
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
AuthResult authResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthenticatedRegistrarAccessor registrarAccessor =
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
new AuthenticatedRegistrarAccessor(
|
new AuthenticatedRegistrarAccessor(
|
||||||
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
authResult, ADMIN_REGISTRAR_ID, SUPPORT_GROUP, lazyGroupsConnection);
|
||||||
|
|
|
@ -18,7 +18,6 @@ import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.request.auth.AuthModule.BEARER_PREFIX;
|
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.IAP_HEADER_NAME;
|
||||||
import static google.registry.request.auth.AuthModule.PROXY_HEADER_NAME;
|
|
||||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -92,9 +91,8 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAuthResultBypass() {
|
void testAuthResultBypass() {
|
||||||
OidcTokenAuthenticationMechanism.setAuthResultForTesting(AuthResult.create(AuthLevel.APP));
|
OidcTokenAuthenticationMechanism.setAuthResultForTesting(AuthResult.NOT_AUTHENTICATED);
|
||||||
assertThat(authenticationMechanism.authenticate(null))
|
assertThat(authenticationMechanism.authenticate(null)).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||||
.isEqualTo(AuthResult.create(AuthLevel.APP));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -169,16 +167,10 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||||
void testRegular_tokenExtractor() throws Exception {
|
void testRegular_tokenExtractor() throws Exception {
|
||||||
useRegularOidcMechanism();
|
useRegularOidcMechanism();
|
||||||
// The token does not have the "Bearer " prefix.
|
// The token does not have the "Bearer " prefix.
|
||||||
when(request.getHeader(PROXY_HEADER_NAME)).thenReturn(rawToken);
|
when(request.getHeader(AUTHORIZATION)).thenReturn(rawToken);
|
||||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isNull();
|
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isNull();
|
||||||
|
|
||||||
// The token is in the correct format.
|
// 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))
|
when(request.getHeader(AUTHORIZATION))
|
||||||
.thenReturn(String.format("%s%s", BEARER_PREFIX, rawToken));
|
.thenReturn(String.format("%s%s", BEARER_PREFIX, rawToken));
|
||||||
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isEqualTo(rawToken);
|
assertThat(authenticationMechanism.tokenExtractor.extract(request)).isEqualTo(rawToken);
|
||||||
|
|
|
@ -14,361 +14,276 @@
|
||||||
|
|
||||||
package google.registry.request.auth;
|
package google.registry.request.auth;
|
||||||
|
|
||||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth8.assertThat;
|
import static com.google.common.truth.Truth8.assertThat;
|
||||||
|
import static google.registry.request.auth.AuthResult.NOT_AUTHENTICATED;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthLevel.APP;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthLevel.NONE;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthLevel.USER;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthMethod.API;
|
||||||
|
import static google.registry.request.auth.AuthSettings.AuthMethod.LEGACY;
|
||||||
|
import static google.registry.request.auth.AuthSettings.UserPolicy.ADMIN;
|
||||||
|
import static google.registry.request.auth.AuthSettings.UserPolicy.PUBLIC;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
|
||||||
import com.google.appengine.api.users.UserService;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import google.registry.model.console.GlobalRole;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.model.console.User;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.model.console.UserRoles;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||||
import google.registry.request.auth.AuthSettings.AuthMethod;
|
import google.registry.request.auth.AuthSettings.AuthMethod;
|
||||||
import google.registry.request.auth.AuthSettings.UserPolicy;
|
import google.registry.request.auth.AuthSettings.UserPolicy;
|
||||||
import google.registry.security.XsrfTokenManager;
|
|
||||||
import google.registry.testing.FakeClock;
|
|
||||||
import google.registry.testing.FakeOAuthService;
|
|
||||||
import google.registry.testing.FakeUserService;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
|
|
||||||
/** Unit tests for {@link RequestAuthenticator}. */
|
/** Unit tests for {@link RequestAuthenticator}. */
|
||||||
class RequestAuthenticatorTest {
|
class RequestAuthenticatorTest {
|
||||||
|
|
||||||
@RegisterExtension
|
private static final AuthResult APP_AUTH = AuthResult.createApp("app@registry.example");
|
||||||
final JpaIntegrationTestExtension jpa =
|
|
||||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
|
||||||
|
|
||||||
private static final AuthSettings AUTH_NONE =
|
private static final AuthResult USER_PUBLIC_AUTH =
|
||||||
AuthSettings.create(ImmutableList.of(AuthMethod.API), AuthLevel.NONE, UserPolicy.PUBLIC);
|
AuthResult.createUser(
|
||||||
|
UserAuthInfo.create(
|
||||||
|
new User.Builder()
|
||||||
|
.setEmailAddress("user@registry.example")
|
||||||
|
.setUserRoles(
|
||||||
|
new UserRoles.Builder()
|
||||||
|
.setIsAdmin(false)
|
||||||
|
.setGlobalRole(GlobalRole.NONE)
|
||||||
|
.build())
|
||||||
|
.build()));
|
||||||
|
|
||||||
private static final AuthSettings AUTH_ANY_USER_ANY_METHOD =
|
private static final AuthResult USER_ADMIN_AUTH =
|
||||||
AuthSettings.create(
|
AuthResult.createUser(
|
||||||
ImmutableList.of(AuthMethod.API, AuthMethod.LEGACY), AuthLevel.USER, UserPolicy.PUBLIC);
|
UserAuthInfo.create(
|
||||||
|
new User.Builder()
|
||||||
|
.setEmailAddress("admin@registry.example")
|
||||||
|
.setUserRoles(
|
||||||
|
new UserRoles.Builder()
|
||||||
|
.setIsAdmin(true)
|
||||||
|
.setGlobalRole(GlobalRole.FTE)
|
||||||
|
.build())
|
||||||
|
.build()));
|
||||||
|
|
||||||
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_NO_METHODS =
|
|
||||||
AuthSettings.create(ImmutableList.of(), AuthLevel.APP, UserPolicy.PUBLIC);
|
|
||||||
|
|
||||||
private static final AuthSettings AUTH_WRONG_METHOD_ORDERING =
|
|
||||||
AuthSettings.create(
|
|
||||||
ImmutableList.of(AuthMethod.LEGACY, AuthMethod.API), AuthLevel.APP, UserPolicy.PUBLIC);
|
|
||||||
|
|
||||||
private static final AuthSettings AUTH_DUPLICATE_METHODS =
|
|
||||||
AuthSettings.create(
|
|
||||||
ImmutableList.of(AuthMethod.API, AuthMethod.API), AuthLevel.APP, UserPolicy.PUBLIC);
|
|
||||||
|
|
||||||
private static final AuthSettings AUTH_NONE_REQUIRES_ADMIN =
|
|
||||||
AuthSettings.create(ImmutableList.of(AuthMethod.API), AuthLevel.NONE, UserPolicy.ADMIN);
|
|
||||||
|
|
||||||
private final UserService mockUserService = mock(UserService.class);
|
|
||||||
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
||||||
|
|
||||||
private final User testUser = new User("test@google.com", "test@google.com");
|
private final AuthenticationMechanism apiAuthenticationMechanism1 =
|
||||||
private final FakeUserService fakeUserService = new FakeUserService();
|
mock(AuthenticationMechanism.class);
|
||||||
private final XsrfTokenManager xsrfTokenManager =
|
private final AuthenticationMechanism apiAuthenticationMechanism2 =
|
||||||
new XsrfTokenManager(new FakeClock(), fakeUserService);
|
mock(AuthenticationMechanism.class);
|
||||||
private final FakeOAuthService fakeOAuthService =
|
private final LegacyAuthenticationMechanism legacyAuthenticationMechanism =
|
||||||
new FakeOAuthService(
|
mock(LegacyAuthenticationMechanism.class);
|
||||||
false /* isOAuthEnabled */,
|
|
||||||
testUser,
|
private Optional<AuthResult> authorize(AuthLevel authLevel, UserPolicy userPolicy) {
|
||||||
false /* isUserAdmin */,
|
return new RequestAuthenticator(
|
||||||
"test-client-id",
|
ImmutableList.of(apiAuthenticationMechanism1, apiAuthenticationMechanism2),
|
||||||
ImmutableList.of("test-scope1", "test-scope2", "nontest-scope"));
|
legacyAuthenticationMechanism)
|
||||||
|
.authorize(AuthSettings.create(ImmutableList.of(API, LEGACY), authLevel, userPolicy), req);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthResult authenticate(AuthMethod... methods) {
|
||||||
|
return new RequestAuthenticator(
|
||||||
|
ImmutableList.of(apiAuthenticationMechanism1, apiAuthenticationMechanism2),
|
||||||
|
legacyAuthenticationMechanism)
|
||||||
|
.authenticate(AuthSettings.create(ImmutableList.copyOf(methods), NONE, PUBLIC), req);
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() {
|
void beforeEach() {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(NOT_AUTHENTICATED);
|
||||||
}
|
when(apiAuthenticationMechanism2.authenticate(req)).thenReturn(NOT_AUTHENTICATED);
|
||||||
|
when(legacyAuthenticationMechanism.authenticate(req)).thenReturn(NOT_AUTHENTICATED);
|
||||||
private RequestAuthenticator createRequestAuthenticator(UserService userService) {
|
|
||||||
return new RequestAuthenticator(
|
|
||||||
ImmutableList.of(
|
|
||||||
new OAuthAuthenticationMechanism(
|
|
||||||
fakeOAuthService,
|
|
||||||
ImmutableSet.of("test-scope1", "test-scope2", "test-scope3"),
|
|
||||||
ImmutableSet.of("test-scope1", "test-scope2"),
|
|
||||||
ImmutableSet.of("test-client-id", "other-test-client-id"))),
|
|
||||||
new LegacyAuthenticationMechanism(userService, xsrfTokenManager));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<AuthResult> runTest(UserService userService, AuthSettings auth) {
|
|
||||||
return createRequestAuthenticator(userService).authorize(auth, req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNoAuthNeeded_noneFound() {
|
void testAuthorize_noneRequired() {
|
||||||
Optional<AuthResult> authResult = runTest(mockUserService, AUTH_NONE);
|
for (AuthResult resultFound :
|
||||||
|
ImmutableList.of(NOT_AUTHENTICATED, APP_AUTH, USER_ADMIN_AUTH, USER_PUBLIC_AUTH)) {
|
||||||
verifyNoInteractions(mockUserService);
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
assertThat(authResult).isPresent();
|
assertThat(authorize(NONE, PUBLIC)).hasValue(resultFound);
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.NONE);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAnyUserAnyMethod_notLoggedIn() {
|
void testAuthorize_appPublicRequired() {
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_ANY_METHOD);
|
authorize(APP, PUBLIC);
|
||||||
|
assertThat(authorize(APP, PUBLIC)).isEmpty();
|
||||||
|
|
||||||
assertThat(authResult).isEmpty();
|
for (AuthResult resultFound : ImmutableList.of(APP_AUTH, USER_ADMIN_AUTH, USER_PUBLIC_AUTH)) {
|
||||||
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
|
assertThat(authorize(APP, PUBLIC)).hasValue(resultFound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAnyUserAnyMethod_xsrfFailure() {
|
void testAuthorize_appAdminRequired() {
|
||||||
fakeUserService.setUser(testUser, false);
|
for (AuthResult resultFound : ImmutableList.of(NOT_AUTHENTICATED, USER_PUBLIC_AUTH)) {
|
||||||
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
|
assertThat(authorize(APP, ADMIN)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_ANY_METHOD);
|
for (AuthResult resultFound : ImmutableList.of(APP_AUTH, USER_ADMIN_AUTH)) {
|
||||||
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
assertThat(authResult).isEmpty();
|
assertThat(authorize(APP, ADMIN)).hasValue(resultFound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAnyUserAnyMethod_success() {
|
void testAuthorize_userPublicRequired() {
|
||||||
fakeUserService.setUser(testUser, false /* isAdmin */);
|
for (AuthResult resultFound : ImmutableList.of(NOT_AUTHENTICATED, APP_AUTH)) {
|
||||||
when(req.getHeader(XsrfTokenManager.X_CSRF_TOKEN))
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
.thenReturn(xsrfTokenManager.generateToken(testUser.getEmail()));
|
assertThat(authorize(USER, PUBLIC)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_ANY_METHOD);
|
for (AuthResult resultFound : ImmutableList.of(USER_PUBLIC_AUTH, USER_ADMIN_AUTH)) {
|
||||||
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
assertThat(authResult).isPresent();
|
assertThat(authorize(USER, PUBLIC)).hasValue(resultFound);
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
}
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().isUserAdmin()).isFalse();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAnyUserAnyMethod_xsrfNotRequiredForGet() {
|
void testAuthorize_userAdminRequired() {
|
||||||
fakeUserService.setUser(testUser, false);
|
for (AuthResult resultFound : ImmutableList.of(NOT_AUTHENTICATED, APP_AUTH, USER_PUBLIC_AUTH)) {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(resultFound);
|
||||||
|
assertThat(authorize(USER, ADMIN)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_ANY_METHOD);
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(USER_ADMIN_AUTH);
|
||||||
|
assertThat(authorize(USER, ADMIN)).hasValue(USER_ADMIN_AUTH);
|
||||||
assertThat(authResult).isPresent();
|
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAdminUserAnyMethod_notLoggedIn() {
|
void testAuthenticate_apiFirst() {
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ADMIN_USER_ANY_METHOD);
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(APP_AUTH);
|
||||||
|
assertThat(authenticate(API, LEGACY)).isEqualTo(APP_AUTH);
|
||||||
assertThat(authResult).isEmpty();
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAdminUserAnyMethod_notAdminUser() {
|
void testAuthenticate_apiSecond() {
|
||||||
fakeUserService.setUser(testUser, false /* isAdmin */);
|
when(apiAuthenticationMechanism2.authenticate(req)).thenReturn(APP_AUTH);
|
||||||
|
assertThat(authenticate(API, LEGACY)).isEqualTo(APP_AUTH);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ADMIN_USER_ANY_METHOD);
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
|
verify(apiAuthenticationMechanism2).authenticate(req);
|
||||||
assertThat(authResult).isEmpty();
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAdminUserAnyMethod_xsrfFailure() {
|
void testAuthenticate_legacy() {
|
||||||
fakeUserService.setUser(testUser, true);
|
when(legacyAuthenticationMechanism.authenticate(req)).thenReturn(APP_AUTH);
|
||||||
|
assertThat(authenticate(API, LEGACY)).isEqualTo(APP_AUTH);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ADMIN_USER_ANY_METHOD);
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
|
verify(apiAuthenticationMechanism2).authenticate(req);
|
||||||
assertThat(authResult).isEmpty();
|
verify(legacyAuthenticationMechanism).authenticate(req);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAdminUserAnyMethod_success() {
|
void testAuthenticate_returnFirstResult() {
|
||||||
fakeUserService.setUser(testUser, true /* isAdmin */);
|
// API auth 2 returns an authenticted auth result, so we don't bother trying the next auth
|
||||||
when(req.getHeader(XsrfTokenManager.X_CSRF_TOKEN))
|
// (legacy auth).
|
||||||
.thenReturn(xsrfTokenManager.generateToken(testUser.getEmail()));
|
when(apiAuthenticationMechanism2.authenticate(req)).thenReturn(APP_AUTH);
|
||||||
|
when(legacyAuthenticationMechanism.authenticate(req)).thenReturn(USER_PUBLIC_AUTH);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ADMIN_USER_ANY_METHOD);
|
assertThat(authenticate(API, LEGACY)).isEqualTo(APP_AUTH);
|
||||||
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
assertThat(authResult).isPresent();
|
verify(apiAuthenticationMechanism2).authenticate(req);
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
assertThat(authResult.get().userAuthInfo().get().isUserAdmin()).isTrue();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testOAuth_success() {
|
void testAuthenticate_notAuthenticated() {
|
||||||
fakeOAuthService.setUser(testUser);
|
assertThat(authenticate(API, LEGACY)).isEqualTo(NOT_AUTHENTICATED);
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
verify(apiAuthenticationMechanism2).authenticate(req);
|
||||||
|
verify(legacyAuthenticationMechanism).authenticate(req);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
assertThat(authResult).isPresent();
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().isUserAdmin()).isFalse();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().authorizedScopes())
|
|
||||||
.containsAtLeast("test-scope1", "test-scope2");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().oauthClientId())
|
|
||||||
.isEqualTo("test-client-id");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().rawAccessToken())
|
|
||||||
.isEqualTo("TOKEN");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testOAuthAdmin_success() {
|
void testAuthenticate_apiOnly() {
|
||||||
fakeOAuthService.setUser(testUser);
|
when(legacyAuthenticationMechanism.authenticate(req)).thenReturn(USER_PUBLIC_AUTH);
|
||||||
fakeOAuthService.setUserAdmin(true);
|
assertThat(authenticate(API)).isEqualTo(NOT_AUTHENTICATED);
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
verify(apiAuthenticationMechanism1).authenticate(req);
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
verify(apiAuthenticationMechanism2).authenticate(req);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
assertThat(authResult).isPresent();
|
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().isUserAdmin()).isTrue();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().authorizedScopes())
|
|
||||||
.containsAtLeast("test-scope1", "test-scope2");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().oauthClientId())
|
|
||||||
.isEqualTo("test-client-id");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().rawAccessToken())
|
|
||||||
.isEqualTo("TOKEN");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testOAuthMissingAuthenticationToken_failure() {
|
void testAuthenticate_legacyOnly() {
|
||||||
fakeOAuthService.setUser(testUser);
|
when(apiAuthenticationMechanism1.authenticate(req)).thenReturn(USER_PUBLIC_AUTH);
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
assertThat(authenticate(LEGACY)).isEqualTo(NOT_AUTHENTICATED);
|
||||||
|
verify(legacyAuthenticationMechanism).authenticate(req);
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
verifyNoMoreInteractions(apiAuthenticationMechanism1);
|
||||||
|
verifyNoMoreInteractions(apiAuthenticationMechanism2);
|
||||||
assertThat(authResult).isEmpty();
|
verifyNoMoreInteractions(legacyAuthenticationMechanism);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testOAuthClientIdMismatch_failure() {
|
void testFailure_checkAuthConfig_noMethods() {
|
||||||
fakeOAuthService.setUser(testUser);
|
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
|
||||||
fakeOAuthService.setClientId("wrong-client-id");
|
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
|
||||||
|
|
||||||
assertThat(authResult).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testOAuthNoScopes_failure() {
|
|
||||||
fakeOAuthService.setUser(testUser);
|
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
|
||||||
fakeOAuthService.setAuthorizedScopes();
|
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
|
||||||
|
|
||||||
assertThat(authResult).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testOAuthMissingScope_failure() {
|
|
||||||
fakeOAuthService.setUser(testUser);
|
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
|
||||||
fakeOAuthService.setAuthorizedScopes("test-scope1", "test-scope3");
|
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
|
||||||
|
|
||||||
assertThat(authResult).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testOAuthExtraScope_success() {
|
|
||||||
fakeOAuthService.setUser(testUser);
|
|
||||||
fakeOAuthService.setOAuthEnabled(true);
|
|
||||||
fakeOAuthService.setAuthorizedScopes("test-scope1", "test-scope2", "test-scope3");
|
|
||||||
when(req.getHeader(AUTHORIZATION)).thenReturn("Bearer TOKEN");
|
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
|
||||||
|
|
||||||
assertThat(authResult).isPresent();
|
|
||||||
assertThat(authResult.get().authLevel()).isEqualTo(AuthLevel.USER);
|
|
||||||
assertThat(authResult.get().userAuthInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().appEngineUser()).hasValue(testUser);
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().isUserAdmin()).isFalse();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo()).isPresent();
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().authorizedScopes())
|
|
||||||
.containsAtLeast("test-scope1", "test-scope2", "test-scope3");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().oauthClientId())
|
|
||||||
.isEqualTo("test-client-id");
|
|
||||||
assertThat(authResult.get().userAuthInfo().get().oauthTokenInfo().get().rawAccessToken())
|
|
||||||
.isEqualTo("TOKEN");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testAnyUserNoLegacy_failureWithLegacyUser() {
|
|
||||||
fakeUserService.setUser(testUser, false /* isAdmin */);
|
|
||||||
|
|
||||||
Optional<AuthResult> authResult = runTest(fakeUserService, AUTH_ANY_USER_NO_LEGACY);
|
|
||||||
|
|
||||||
assertThat(authResult).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCheckAuthConfig_noMethods_failure() {
|
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() -> RequestAuthenticator.checkAuthConfig(AUTH_NO_METHODS));
|
() ->
|
||||||
|
RequestAuthenticator.checkAuthConfig(
|
||||||
|
AuthSettings.create(ImmutableList.of(), NONE, PUBLIC)));
|
||||||
assertThat(thrown).hasMessageThat().contains("Must specify at least one auth method");
|
assertThat(thrown).hasMessageThat().contains("Must specify at least one auth method");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCheckAuthConfig_wrongMethodOrdering_failure() {
|
void testFailure_checkAuthConfig_wrongMethodOrder() {
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() -> RequestAuthenticator.checkAuthConfig(AUTH_WRONG_METHOD_ORDERING));
|
() ->
|
||||||
|
RequestAuthenticator.checkAuthConfig(
|
||||||
|
AuthSettings.create(ImmutableList.of(LEGACY, API), NONE, PUBLIC)));
|
||||||
assertThat(thrown)
|
assertThat(thrown)
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains("Auth methods must be unique and strictly in order - API, LEGACY");
|
.contains("Auth methods must be unique and strictly in order - API, LEGACY");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCheckAuthConfig_noneAuthLevelRequiresAdmin_failure() {
|
void testFailure_CheckAuthConfig_duplicateMethods() {
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() -> RequestAuthenticator.checkAuthConfig(AUTH_NONE_REQUIRES_ADMIN));
|
() ->
|
||||||
|
RequestAuthenticator.checkAuthConfig(
|
||||||
|
AuthSettings.create(ImmutableList.of(API, API), NONE, PUBLIC)));
|
||||||
|
assertThat(thrown)
|
||||||
|
.hasMessageThat()
|
||||||
|
.contains("Auth methods must be unique and strictly in order - API, LEGACY");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_checkAuthConfig_noneAuthLevelRequiresAdmin() {
|
||||||
|
IllegalArgumentException thrown =
|
||||||
|
assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() ->
|
||||||
|
RequestAuthenticator.checkAuthConfig(
|
||||||
|
AuthSettings.create(ImmutableList.of(API, LEGACY), NONE, ADMIN)));
|
||||||
assertThat(thrown)
|
assertThat(thrown)
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains("Actions with minimal auth level at NONE should not specify ADMIN user policy");
|
.contains("Actions with minimal auth level at NONE should not specify ADMIN user policy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCheckAuthConfig_DuplicateMethods_failure() {
|
|
||||||
IllegalArgumentException thrown =
|
|
||||||
assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> RequestAuthenticator.checkAuthConfig(AUTH_DUPLICATE_METHODS));
|
|
||||||
assertThat(thrown)
|
|
||||||
.hasMessageThat()
|
|
||||||
.contains("Auth methods must be unique and strictly in order - API, LEGACY");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,15 @@ package google.registry.security;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
import com.google.appengine.api.users.User;
|
||||||
|
import com.google.appengine.api.users.UserService;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeUserService;
|
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -37,14 +39,16 @@ class XsrfTokenManagerTest {
|
||||||
|
|
||||||
private final User testUser = new User("test@example.com", "test@example.com");
|
private final User testUser = new User("test@example.com", "test@example.com");
|
||||||
private final FakeClock clock = new FakeClock(START_OF_TIME);
|
private final FakeClock clock = new FakeClock(START_OF_TIME);
|
||||||
private final FakeUserService userService = new FakeUserService();
|
private final UserService userService = mock(UserService.class);
|
||||||
private final XsrfTokenManager xsrfTokenManager = new XsrfTokenManager(clock, userService);
|
private final XsrfTokenManager xsrfTokenManager = new XsrfTokenManager(clock, userService);
|
||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() {
|
void beforeEach() {
|
||||||
userService.setUser(testUser, false);
|
when(userService.isUserLoggedIn()).thenReturn(true);
|
||||||
|
when(userService.getCurrentUser()).thenReturn(testUser);
|
||||||
|
when(userService.isUserAdmin()).thenReturn(false);
|
||||||
token = xsrfTokenManager.generateToken(testUser.getEmail());
|
token = xsrfTokenManager.generateToken(testUser.getEmail());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ public final class RegistryTestServer {
|
||||||
|
|
||||||
private final TestServer server;
|
private final TestServer server;
|
||||||
|
|
||||||
/** @see TestServer#TestServer(HostAndPort, ImmutableMap, ImmutableList, ImmutableList) */
|
/** @see TestServer#TestServer(HostAndPort, ImmutableMap, ImmutableList) */
|
||||||
public RegistryTestServer(HostAndPort address) {
|
public RegistryTestServer(HostAndPort address) {
|
||||||
server = new TestServer(address, RUNFILES, ROUTES);
|
server = new TestServer(address, RUNFILES, ROUTES);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ public final class RegistryTestServer {
|
||||||
server.stop();
|
server.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see TestServer#getUrl(java.lang.String) */
|
/** @see TestServer#getUrl(String) */
|
||||||
public URL getUrl(String path) {
|
public URL getUrl(String path) {
|
||||||
return server.getUrl(path);
|
return server.getUrl(path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import google.registry.model.console.UserRoles;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism;
|
import google.registry.request.auth.OidcTokenAuthenticationMechanism;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.UserInfo;
|
import google.registry.testing.UserInfo;
|
||||||
|
@ -148,7 +147,7 @@ public final class RegistryTestServerMain {
|
||||||
.setRegistryLockPassword("registryLockPassword")
|
.setRegistryLockPassword("registryLockPassword")
|
||||||
.build();
|
.build();
|
||||||
OidcTokenAuthenticationMechanism.setAuthResultForTesting(
|
OidcTokenAuthenticationMechanism.setAuthResultForTesting(
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user)));
|
AuthResult.createUser(UserAuthInfo.create(user)));
|
||||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension().beforeEach(null);
|
new JpaTestExtensions.Builder().buildIntegrationTestExtension().beforeEach(null);
|
||||||
JpaTransactionManagerExtension.loadInitialData();
|
JpaTransactionManagerExtension.loadInitialData();
|
||||||
System.out.printf("%sLoading fixtures...%s\n", BLUE, RESET);
|
System.out.printf("%sLoading fixtures...%s\n", BLUE, RESET);
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
// Copyright 2017 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.testing;
|
|
||||||
|
|
||||||
import com.google.appengine.api.oauth.OAuthRequestException;
|
|
||||||
import com.google.appengine.api.oauth.OAuthService;
|
|
||||||
import com.google.appengine.api.users.User;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** A fake {@link OAuthService} implementation for testing. */
|
|
||||||
public class FakeOAuthService implements OAuthService {
|
|
||||||
|
|
||||||
private boolean isOAuthEnabled;
|
|
||||||
private User currentUser;
|
|
||||||
private boolean isUserAdmin;
|
|
||||||
private String clientId;
|
|
||||||
private ImmutableList<String> authorizedScopes;
|
|
||||||
|
|
||||||
public FakeOAuthService(
|
|
||||||
boolean isOAuthEnabled,
|
|
||||||
User currentUser,
|
|
||||||
boolean isUserAdmin,
|
|
||||||
String clientId,
|
|
||||||
List<String> authorizedScopes) {
|
|
||||||
this.isOAuthEnabled = isOAuthEnabled;
|
|
||||||
this.currentUser = currentUser;
|
|
||||||
this.isUserAdmin = isUserAdmin;
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.authorizedScopes = ImmutableList.copyOf(authorizedScopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOAuthEnabled(boolean isOAuthEnabled) {
|
|
||||||
this.isOAuthEnabled = isOAuthEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(User currentUser) {
|
|
||||||
this.currentUser = currentUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserAdmin(boolean isUserAdmin) {
|
|
||||||
this.isUserAdmin = isUserAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientId(String clientId) {
|
|
||||||
this.clientId = clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthorizedScopes(String... scopes) {
|
|
||||||
this.authorizedScopes = ImmutableList.copyOf(scopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getCurrentUser() throws OAuthRequestException {
|
|
||||||
if (!isOAuthEnabled) {
|
|
||||||
throw new OAuthRequestException("invalid OAuth request");
|
|
||||||
}
|
|
||||||
return currentUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getCurrentUser(String scope) throws OAuthRequestException {
|
|
||||||
return getCurrentUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getCurrentUser(String... scopes) throws OAuthRequestException {
|
|
||||||
return getCurrentUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUserAdmin() throws OAuthRequestException {
|
|
||||||
if (!isOAuthEnabled) {
|
|
||||||
throw new OAuthRequestException("invalid OAuth request");
|
|
||||||
}
|
|
||||||
return isUserAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUserAdmin(String scope) throws OAuthRequestException {
|
|
||||||
return isUserAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUserAdmin(String... scopes) throws OAuthRequestException {
|
|
||||||
return isUserAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getClientId(String scope) throws OAuthRequestException {
|
|
||||||
if (!isOAuthEnabled) {
|
|
||||||
throw new OAuthRequestException("invalid OAuth request");
|
|
||||||
}
|
|
||||||
return clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getClientId(String... scopes) throws OAuthRequestException {
|
|
||||||
if (!isOAuthEnabled) {
|
|
||||||
throw new OAuthRequestException("invalid OAuth request");
|
|
||||||
}
|
|
||||||
return clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getAuthorizedScopes(String... scopes) throws OAuthRequestException {
|
|
||||||
if (!isOAuthEnabled) {
|
|
||||||
throw new OAuthRequestException("invalid OAuth request");
|
|
||||||
}
|
|
||||||
return authorizedScopes.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public String getOAuthConsumerKey() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright 2017 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.testing;
|
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
|
||||||
import com.google.appengine.api.users.UserService;
|
|
||||||
import google.registry.model.annotations.DeleteAfterMigration;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/** Fake implementation of {@link UserService} for testing. */
|
|
||||||
@DeleteAfterMigration
|
|
||||||
public class FakeUserService implements UserService {
|
|
||||||
|
|
||||||
@Nullable private User user = null;
|
|
||||||
private boolean isAdmin = false;
|
|
||||||
|
|
||||||
public void setUser(@Nullable User user, boolean isAdmin) {
|
|
||||||
this.user = user;
|
|
||||||
this.isAdmin = isAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createLoginURL(String destinationURL) {
|
|
||||||
return String.format("/login?dest=%s", destinationURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createLoginURL(String destinationURL, String authDomain) {
|
|
||||||
return createLoginURL(destinationURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public String createLoginURL(String destinationURL, String authDomain, String federatedIdentity,
|
|
||||||
Set<String> attributesRequest) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createLogoutURL(String destinationURL) {
|
|
||||||
return String.format("/logout?dest=%s", destinationURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createLogoutURL(String destinationURL, String authDomain) {
|
|
||||||
return createLogoutURL(destinationURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUserLoggedIn() {
|
|
||||||
return user != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUserAdmin() {
|
|
||||||
return isAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getCurrentUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -72,7 +72,7 @@ class AuthModuleTest {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// We need to set the following fields because they are checked when
|
// We need to set the following fields because they are checked when
|
||||||
// Credential#setRefreshToken is called. However they are not actually persisted in the
|
// Credential#setRefreshToken is called. However, they are not actually persisted in the
|
||||||
// DataStore and not actually used in tests.
|
// DataStore and not actually used in tests.
|
||||||
.setJsonFactory(new GsonFactory())
|
.setJsonFactory(new GsonFactory())
|
||||||
.setTransport(new NetHttpTransport())
|
.setTransport(new NetHttpTransport())
|
||||||
|
@ -104,7 +104,7 @@ class AuthModuleTest {
|
||||||
AuthModule.provideClientScopeQualifier("client-id", ImmutableList.of("foo", "bar"));
|
AuthModule.provideClientScopeQualifier("client-id", ImmutableList.of("foo", "bar"));
|
||||||
|
|
||||||
// If we change the way we encode client id and scopes, this assertion will break. That's
|
// If we change the way we encode client id and scopes, this assertion will break. That's
|
||||||
// probably ok and you can just change the text. The things you have to be aware of are:
|
// probably ok, and you can just change the text. The things you have to be aware of are:
|
||||||
// - Names in the new encoding should have a low risk of collision with the old encoding.
|
// - Names in the new encoding should have a low risk of collision with the old encoding.
|
||||||
// - Changing the encoding will force all OAuth users of the nomulus tool to do a new login
|
// - Changing the encoding will force all OAuth users of the nomulus tool to do a new login
|
||||||
// (existing credentials will not be used).
|
// (existing credentials will not be used).
|
||||||
|
@ -155,7 +155,7 @@ class AuthModuleTest {
|
||||||
AuthModule.provideClientScopeQualifier(AuthModule.provideClientId(clientSecrets), scopes));
|
AuthModule.provideClientScopeQualifier(AuthModule.provideClientId(clientSecrets), scopes));
|
||||||
}
|
}
|
||||||
|
|
||||||
private GoogleClientSecrets getSecrets() {
|
private static GoogleClientSecrets getSecrets() {
|
||||||
return new GoogleClientSecrets()
|
return new GoogleClientSecrets()
|
||||||
.setInstalled(
|
.setInstalled(
|
||||||
AuthModule.provideDefaultInstalledDetails()
|
AuthModule.provideDefaultInstalledDetails()
|
||||||
|
@ -166,7 +166,8 @@ class AuthModuleTest {
|
||||||
@Test
|
@Test
|
||||||
void test_provideLocalCredentialJson() {
|
void test_provideLocalCredentialJson() {
|
||||||
String credentialJson =
|
String credentialJson =
|
||||||
AuthModule.provideLocalCredentialJson(this::getSecrets, this::getCredential, null);
|
AuthModule.provideLocalCredentialJson(
|
||||||
|
AuthModuleTest::getSecrets, this::getCredential, null);
|
||||||
Map<String, String> jsonMap =
|
Map<String, String> jsonMap =
|
||||||
new Gson().fromJson(credentialJson, new TypeToken<Map<String, String>>() {}.getType());
|
new Gson().fromJson(credentialJson, new TypeToken<Map<String, String>>() {}.getType());
|
||||||
assertThat(jsonMap.get("type")).isEqualTo("authorized_user");
|
assertThat(jsonMap.get("type")).isEqualTo("authorized_user");
|
||||||
|
@ -182,7 +183,7 @@ class AuthModuleTest {
|
||||||
Files.write(credentialFile.toPath(), "{some_field: some_value}".getBytes(UTF_8));
|
Files.write(credentialFile.toPath(), "{some_field: some_value}".getBytes(UTF_8));
|
||||||
String credentialJson =
|
String credentialJson =
|
||||||
AuthModule.provideLocalCredentialJson(
|
AuthModule.provideLocalCredentialJson(
|
||||||
this::getSecrets, this::getCredential, credentialFile.getCanonicalPath());
|
AuthModuleTest::getSecrets, this::getCredential, credentialFile.getCanonicalPath());
|
||||||
assertThat(credentialJson).isEqualTo("{some_field: some_value}");
|
assertThat(credentialJson).isEqualTo("{some_field: some_value}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.tools.RequestFactoryModule.REQUEST_TIMEOUT_MS;
|
import static google.registry.tools.RequestFactoryModule.REQUEST_TIMEOUT_MS;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
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.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.api.client.http.GenericUrl;
|
import com.google.api.client.http.GenericUrl;
|
||||||
|
@ -35,6 +32,7 @@ import com.google.auth.oauth2.UserCredentials;
|
||||||
import google.registry.config.RegistryConfig;
|
import google.registry.config.RegistryConfig;
|
||||||
import google.registry.testing.SystemPropertyExtension;
|
import google.registry.testing.SystemPropertyExtension;
|
||||||
import google.registry.util.GoogleCredentialsBundle;
|
import google.registry.util.GoogleCredentialsBundle;
|
||||||
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -50,7 +48,6 @@ public class RequestFactoryModuleTest {
|
||||||
final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension();
|
final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension();
|
||||||
|
|
||||||
@Mock public GoogleCredentialsBundle credentialsBundle;
|
@Mock public GoogleCredentialsBundle credentialsBundle;
|
||||||
@Mock public HttpRequestInitializer httpRequestInitializer;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() {
|
void beforeEach() {
|
||||||
|
@ -64,12 +61,11 @@ public class RequestFactoryModuleTest {
|
||||||
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = true;
|
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = true;
|
||||||
try {
|
try {
|
||||||
HttpRequestFactory factory =
|
HttpRequestFactory factory =
|
||||||
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle, "client-id", false);
|
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle, "client-id");
|
||||||
HttpRequestInitializer initializer = factory.getInitializer();
|
HttpRequestInitializer initializer = factory.getInitializer();
|
||||||
assertThat(initializer).isNotNull();
|
assertThat(initializer).isNotNull();
|
||||||
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
|
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
|
||||||
initializer.initialize(request);
|
initializer.initialize(request);
|
||||||
verifyNoInteractions(httpRequestInitializer);
|
|
||||||
} finally {
|
} finally {
|
||||||
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = origIsLocal;
|
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = origIsLocal;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +73,6 @@ public class RequestFactoryModuleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_provideHttpRequestFactory_remote() throws Exception {
|
void test_provideHttpRequestFactory_remote() throws Exception {
|
||||||
when(credentialsBundle.getHttpRequestInitializer()).thenReturn(httpRequestInitializer);
|
|
||||||
// Mock the request/response to/from the OIDC server requesting an ID token
|
// Mock the request/response to/from the OIDC server requesting an ID token
|
||||||
UserCredentials mockUserCredentials = mock(UserCredentials.class);
|
UserCredentials mockUserCredentials = mock(UserCredentials.class);
|
||||||
when(credentialsBundle.getGoogleCredentials()).thenReturn(mockUserCredentials);
|
when(credentialsBundle.getGoogleCredentials()).thenReturn(mockUserCredentials);
|
||||||
|
@ -97,23 +92,15 @@ public class RequestFactoryModuleTest {
|
||||||
boolean origIsLocal = RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal;
|
boolean origIsLocal = RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal;
|
||||||
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = false;
|
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = false;
|
||||||
try {
|
try {
|
||||||
// With OAuth header.
|
|
||||||
HttpRequestFactory factory =
|
HttpRequestFactory factory =
|
||||||
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle, "clientId", true);
|
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle, "clientId");
|
||||||
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
|
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
|
||||||
assertThat(request.getHeaders().get("Proxy-Authorization")).isEqualTo("Bearer oidc.token");
|
@SuppressWarnings("unchecked")
|
||||||
|
List<String> authHeaders = (List<String>) request.getHeaders().get("Authorization");
|
||||||
|
assertThat(authHeaders.size()).isEqualTo(1);
|
||||||
|
assertThat(authHeaders.get(0)).isEqualTo("Bearer oidc.token");
|
||||||
assertThat(request.getConnectTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
assertThat(request.getConnectTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
||||||
assertThat(request.getReadTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
assertThat(request.getReadTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
||||||
verify(httpRequestInitializer).initialize(request);
|
|
||||||
verifyNoMoreInteractions(httpRequestInitializer);
|
|
||||||
// No OAuth header.
|
|
||||||
factory =
|
|
||||||
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle, "clientId", false);
|
|
||||||
request = factory.buildGetRequest(new GenericUrl("http://localhost"));
|
|
||||||
assertThat(request.getHeaders().get("Proxy-Authorization")).isEqualTo("Bearer oidc.token");
|
|
||||||
assertThat(request.getConnectTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
|
||||||
assertThat(request.getReadTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
|
|
||||||
verifyNoMoreInteractions(httpRequestInitializer);
|
|
||||||
} finally {
|
} finally {
|
||||||
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = origIsLocal;
|
RegistryConfig.CONFIG_SETTINGS.get().gcpProject.isLocal = origIsLocal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import google.registry.model.console.UserRoles;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.DatabaseHelper;
|
import google.registry.testing.DatabaseHelper;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
|
@ -55,8 +54,7 @@ public class ConsoleDomainGetActionTest {
|
||||||
void testSuccess_fullJsonRepresentation() {
|
void testSuccess_fullJsonRepresentation() {
|
||||||
ConsoleDomainGetAction action =
|
ConsoleDomainGetAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(
|
createUser(
|
||||||
new UserRoles.Builder()
|
new UserRoles.Builder()
|
||||||
|
@ -85,7 +83,8 @@ public class ConsoleDomainGetActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFailure_appAuth() {
|
void testFailure_appAuth() {
|
||||||
ConsoleDomainGetAction action = createAction(AuthResult.create(AuthLevel.APP), "exists.tld");
|
ConsoleDomainGetAction action =
|
||||||
|
createAction(AuthResult.createApp("service@registry.example"), "exists.tld");
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
@ -94,8 +93,7 @@ public class ConsoleDomainGetActionTest {
|
||||||
void testFailure_wrongTypeOfUser() {
|
void testFailure_wrongTypeOfUser() {
|
||||||
ConsoleDomainGetAction action =
|
ConsoleDomainGetAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(mock(com.google.appengine.api.users.User.class), false)),
|
UserAuthInfo.create(mock(com.google.appengine.api.users.User.class), false)),
|
||||||
"exists.tld");
|
"exists.tld");
|
||||||
action.run();
|
action.run();
|
||||||
|
@ -106,8 +104,7 @@ public class ConsoleDomainGetActionTest {
|
||||||
void testFailure_noAccessToRegistrar() {
|
void testFailure_noAccessToRegistrar() {
|
||||||
ConsoleDomainGetAction action =
|
ConsoleDomainGetAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(UserAuthInfo.create(createUser(new UserRoles.Builder().build()))),
|
||||||
AuthLevel.USER, UserAuthInfo.create(createUser(new UserRoles.Builder().build()))),
|
|
||||||
"exists.tld");
|
"exists.tld");
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
||||||
|
@ -117,8 +114,7 @@ public class ConsoleDomainGetActionTest {
|
||||||
void testFailure_nonexistentDomain() {
|
void testFailure_nonexistentDomain() {
|
||||||
ConsoleDomainGetAction action =
|
ConsoleDomainGetAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))),
|
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))),
|
||||||
"nonexistent.tld");
|
"nonexistent.tld");
|
||||||
action.run();
|
action.run();
|
||||||
|
|
|
@ -24,7 +24,6 @@ import google.registry.model.console.UserRoles;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -50,8 +49,7 @@ class ConsoleUserDataActionTest {
|
||||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ConsoleUserDataAction action =
|
ConsoleUserDataAction action = createAction(AuthResult.createUser(UserAuthInfo.create(user)));
|
||||||
createAction(AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user)));
|
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
||||||
Map jsonObject = GSON.fromJson(response.getPayload(), Map.class);
|
Map jsonObject = GSON.fromJson(response.getPayload(), Map.class);
|
||||||
|
@ -63,8 +61,7 @@ class ConsoleUserDataActionTest {
|
||||||
void testFailure_notAConsoleUser() throws IOException {
|
void testFailure_notAConsoleUser() throws IOException {
|
||||||
ConsoleUserDataAction action =
|
ConsoleUserDataAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
new com.google.appengine.api.users.User(
|
new com.google.appengine.api.users.User(
|
||||||
"JohnDoe@theregistrar.com", "theregistrar.com"),
|
"JohnDoe@theregistrar.com", "theregistrar.com"),
|
||||||
|
|
|
@ -38,7 +38,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.DeterministicStringGenerator;
|
import google.registry.testing.DeterministicStringGenerator;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
|
@ -108,8 +107,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.GET,
|
Action.Method.GET,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(
|
createUser(
|
||||||
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_LEAD).build()))));
|
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_LEAD).build()))));
|
||||||
|
@ -129,8 +127,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.GET,
|
Action.Method.GET,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))));
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))));
|
||||||
action.run();
|
action.run();
|
||||||
|
@ -151,8 +148,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
||||||
|
@ -180,8 +176,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
||||||
action.run();
|
action.run();
|
||||||
|
@ -200,8 +195,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))));
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
|
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
|
||||||
|
@ -215,8 +209,7 @@ class RegistrarsActionTest {
|
||||||
RegistrarsAction action =
|
RegistrarsAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.GET,
|
Action.Method.GET,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(
|
createUser(
|
||||||
new UserRoles.Builder()
|
new UserRoles.Builder()
|
||||||
|
|
|
@ -37,7 +37,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||||
|
@ -103,8 +102,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.GET,
|
Action.Method.GET,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId(),
|
testRegistrar.getRegistrarId(),
|
||||||
|
@ -121,8 +119,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.GET,
|
Action.Method.GET,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId(),
|
testRegistrar.getRegistrarId(),
|
||||||
|
@ -137,8 +134,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId(),
|
testRegistrar.getRegistrarId(),
|
||||||
|
@ -160,8 +156,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId(),
|
testRegistrar.getRegistrarId(),
|
||||||
|
@ -186,8 +181,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId(),
|
testRegistrar.getRegistrarId(),
|
||||||
|
@ -208,8 +202,7 @@ class ContactActionTest {
|
||||||
ContactAction action =
|
ContactAction action =
|
||||||
createAction(
|
createAction(
|
||||||
Action.Method.POST,
|
Action.Method.POST,
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(
|
createUser(
|
||||||
new UserRoles.Builder()
|
new UserRoles.Builder()
|
||||||
|
|
|
@ -35,7 +35,6 @@ import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
@ -92,8 +91,7 @@ class SecurityActionTest {
|
||||||
clock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
clock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
||||||
SecurityAction action =
|
SecurityAction action =
|
||||||
createAction(
|
createAction(
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build()))),
|
||||||
testRegistrar.getRegistrarId());
|
testRegistrar.getRegistrarId());
|
||||||
|
|
|
@ -33,7 +33,6 @@ import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
|
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
|
@ -127,8 +126,7 @@ public class WhoisRegistrarFieldsActionTest {
|
||||||
void testFailure_noAccessToRegistrar() throws Exception {
|
void testFailure_noAccessToRegistrar() throws Exception {
|
||||||
Registrar newRegistrar = Registrar.loadByRegistrarIdCached("NewRegistrar").get();
|
Registrar newRegistrar = Registrar.loadByRegistrarIdCached("NewRegistrar").get();
|
||||||
AuthResult onlyTheRegistrar =
|
AuthResult onlyTheRegistrar =
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
new User.Builder()
|
new User.Builder()
|
||||||
.setEmailAddress("email@email.example")
|
.setEmailAddress("email@email.example")
|
||||||
|
@ -147,8 +145,7 @@ public class WhoisRegistrarFieldsActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthResult defaultUserAuth() {
|
private AuthResult defaultUserAuth() {
|
||||||
return AuthResult.create(
|
return AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(
|
UserAuthInfo.create(
|
||||||
new User.Builder()
|
new User.Builder()
|
||||||
.setEmailAddress("email@email.example")
|
.setEmailAddress("email@email.example")
|
||||||
|
|
|
@ -37,7 +37,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.Action.Method;
|
import google.registry.request.Action.Method;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.security.XsrfTokenManager;
|
import google.registry.security.XsrfTokenManager;
|
||||||
|
@ -93,7 +92,7 @@ public final class ConsoleOteSetupActionTest {
|
||||||
ImmutableSetMultimap.of("unused", AuthenticatedRegistrarAccessor.Role.ADMIN));
|
ImmutableSetMultimap.of("unused", AuthenticatedRegistrarAccessor.Role.ADMIN));
|
||||||
action.userService = UserServiceFactory.getUserService();
|
action.userService = UserServiceFactory.getUserService();
|
||||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
action.authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
action.sendEmailUtils =
|
action.sendEmailUtils =
|
||||||
new SendEmailUtils(
|
new SendEmailUtils(
|
||||||
new InternetAddress("outgoing@registry.example"),
|
new InternetAddress("outgoing@registry.example"),
|
||||||
|
|
|
@ -37,7 +37,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.Action.Method;
|
import google.registry.request.Action.Method;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.security.XsrfTokenManager;
|
import google.registry.security.XsrfTokenManager;
|
||||||
|
@ -93,7 +92,7 @@ final class ConsoleRegistrarCreatorActionTest {
|
||||||
ImmutableSetMultimap.of("unused", AuthenticatedRegistrarAccessor.Role.ADMIN));
|
ImmutableSetMultimap.of("unused", AuthenticatedRegistrarAccessor.Role.ADMIN));
|
||||||
action.userService = UserServiceFactory.getUserService();
|
action.userService = UserServiceFactory.getUserService();
|
||||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
action.authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
action.sendEmailUtils =
|
action.sendEmailUtils =
|
||||||
new SendEmailUtils(
|
new SendEmailUtils(
|
||||||
new InternetAddress("outgoing@registry.example"),
|
new InternetAddress("outgoing@registry.example"),
|
||||||
|
|
|
@ -32,7 +32,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.Action.Method;
|
import google.registry.request.Action.Method;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.security.XsrfTokenManager;
|
import google.registry.security.XsrfTokenManager;
|
||||||
|
@ -78,7 +77,7 @@ class ConsoleUiActionTest {
|
||||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||||
action.method = Method.GET;
|
action.method = Method.GET;
|
||||||
action.paramClientId = Optional.empty();
|
action.paramClientId = Optional.empty();
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
action.authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
action.analyticsConfig = ImmutableMap.of("googleAnalyticsId", "sampleId");
|
action.analyticsConfig = ImmutableMap.of("googleAnalyticsId", "sampleId");
|
||||||
|
|
||||||
action.registrarAccessor =
|
action.registrarAccessor =
|
||||||
|
|
|
@ -44,7 +44,6 @@ import google.registry.request.JsonActionRunner;
|
||||||
import google.registry.request.JsonResponse;
|
import google.registry.request.JsonResponse;
|
||||||
import google.registry.request.ResponseImpl;
|
import google.registry.request.ResponseImpl;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.CloudTasksHelper;
|
import google.registry.testing.CloudTasksHelper;
|
||||||
|
@ -113,8 +112,7 @@ public abstract class RegistrarSettingsActionTestCase {
|
||||||
gmailClient);
|
gmailClient);
|
||||||
action.registrarConsoleMetrics = new RegistrarConsoleMetrics();
|
action.registrarConsoleMetrics = new RegistrarConsoleMetrics();
|
||||||
action.authResult =
|
action.authResult =
|
||||||
AuthResult.create(
|
AuthResult.createUser(
|
||||||
AuthLevel.USER,
|
|
||||||
UserAuthInfo.create(new User("user@email.com", "email.com", "12345"), false));
|
UserAuthInfo.create(new User("user@email.com", "email.com", "12345"), false));
|
||||||
action.certificateChecker =
|
action.certificateChecker =
|
||||||
new CertificateChecker(
|
new CertificateChecker(
|
||||||
|
|
|
@ -40,7 +40,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.Action.Method;
|
import google.registry.request.Action.Method;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
@ -75,7 +74,7 @@ final class RegistryLockGetActionTest {
|
||||||
void beforeEach() {
|
void beforeEach() {
|
||||||
user = userFromRegistrarPoc(makeRegistrarContact3());
|
user = userFromRegistrarPoc(makeRegistrarContact3());
|
||||||
fakeClock.setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
|
fakeClock.setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
|
||||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
accessor =
|
accessor =
|
||||||
AuthenticatedRegistrarAccessor.createForTesting(
|
AuthenticatedRegistrarAccessor.createForTesting(
|
||||||
ImmutableSetMultimap.of(
|
ImmutableSetMultimap.of(
|
||||||
|
@ -109,7 +108,7 @@ final class RegistryLockGetActionTest {
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
action.authResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
||||||
assertThat(GSON.fromJson(response.getPayload(), Map.class))
|
assertThat(GSON.fromJson(response.getPayload(), Map.class))
|
||||||
|
@ -336,7 +335,7 @@ final class RegistryLockGetActionTest {
|
||||||
persistResource(makeRegistrar2().asBuilder().setRegistryLockAllowed(false).build());
|
persistResource(makeRegistrar2().asBuilder().setRegistryLockAllowed(false).build());
|
||||||
// disallow the other user
|
// disallow the other user
|
||||||
persistResource(makeRegistrarContact2().asBuilder().setLoginEmailAddress(null).build());
|
persistResource(makeRegistrarContact2().asBuilder().setLoginEmailAddress(null).build());
|
||||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, true));
|
authResult = AuthResult.createUser(UserAuthInfo.create(user, true));
|
||||||
accessor =
|
accessor =
|
||||||
AuthenticatedRegistrarAccessor.createForTesting(
|
AuthenticatedRegistrarAccessor.createForTesting(
|
||||||
ImmutableSetMultimap.of(
|
ImmutableSetMultimap.of(
|
||||||
|
@ -364,7 +363,7 @@ final class RegistryLockGetActionTest {
|
||||||
void testSuccess_linkedToLoginContactEmail() {
|
void testSuccess_linkedToLoginContactEmail() {
|
||||||
// Note that the email address is case-insensitive.
|
// Note that the email address is case-insensitive.
|
||||||
user = new User("marla.singer@crr.com", "crr.com", user.getUserId());
|
user = new User("marla.singer@crr.com", "crr.com", user.getUserId());
|
||||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
action =
|
action =
|
||||||
new RegistryLockGetAction(
|
new RegistryLockGetAction(
|
||||||
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
|
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
|
||||||
|
|
|
@ -45,7 +45,6 @@ import google.registry.request.JsonActionRunner;
|
||||||
import google.registry.request.JsonResponse;
|
import google.registry.request.JsonResponse;
|
||||||
import google.registry.request.ResponseImpl;
|
import google.registry.request.ResponseImpl;
|
||||||
import google.registry.request.auth.AuthResult;
|
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;
|
||||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
|
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
|
@ -115,8 +114,7 @@ final class RegistryLockPostActionTest {
|
||||||
when(mockRequest.getServerName()).thenReturn("registrarconsole.tld");
|
when(mockRequest.getServerName()).thenReturn("registrarconsole.tld");
|
||||||
|
|
||||||
action =
|
action =
|
||||||
createAction(
|
createAction(AuthResult.createUser(UserAuthInfo.create(userWithLockPermission, false)));
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -154,9 +152,7 @@ final class RegistryLockPostActionTest {
|
||||||
saveRegistryLock(
|
saveRegistryLock(
|
||||||
createLock().asBuilder().isSuperuser(true).setLockCompletionTime(clock.nowUtc()).build());
|
createLock().asBuilder().isSuperuser(true).setLockCompletionTime(clock.nowUtc()).build());
|
||||||
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||||
action =
|
action = createAction(AuthResult.createUser(UserAuthInfo.create(userWithoutPermission, true)));
|
||||||
createAction(
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
|
||||||
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
|
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
|
||||||
// we should still email the admin user's email address
|
// we should still email the admin user's email address
|
||||||
assertSuccess(response, "unlock", "johndoe@theregistrar.com");
|
assertSuccess(response, "unlock", "johndoe@theregistrar.com");
|
||||||
|
@ -166,8 +162,7 @@ final class RegistryLockPostActionTest {
|
||||||
void testSuccess_linkedToLoginEmail() throws Exception {
|
void testSuccess_linkedToLoginEmail() throws Exception {
|
||||||
userWithLockPermission = new User("Marla.Singer@crr.com", "crr.com");
|
userWithLockPermission = new User("Marla.Singer@crr.com", "crr.com");
|
||||||
action =
|
action =
|
||||||
createAction(
|
createAction(AuthResult.createUser(UserAuthInfo.create(userWithLockPermission, false)));
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false)));
|
|
||||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||||
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
||||||
}
|
}
|
||||||
|
@ -205,18 +200,14 @@ final class RegistryLockPostActionTest {
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_adminUser() throws Exception {
|
void testSuccess_adminUser() throws Exception {
|
||||||
// Admin user should be able to lock/unlock regardless -- and we use the admin user's email
|
// Admin user should be able to lock/unlock regardless -- and we use the admin user's email
|
||||||
action =
|
action = createAction(AuthResult.createUser(UserAuthInfo.create(userWithoutPermission, true)));
|
||||||
createAction(
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
|
||||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||||
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_adminUser_doesNotRequirePassword() throws Exception {
|
void testSuccess_adminUser_doesNotRequirePassword() throws Exception {
|
||||||
action =
|
action = createAction(AuthResult.createUser(UserAuthInfo.create(userWithoutPermission, true)));
|
||||||
createAction(
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
|
||||||
Map<String, ?> response =
|
Map<String, ?> response =
|
||||||
action.handleJsonRequest(
|
action.handleJsonRequest(
|
||||||
ImmutableMap.of(
|
ImmutableMap.of(
|
||||||
|
@ -239,8 +230,7 @@ final class RegistryLockPostActionTest {
|
||||||
.build())
|
.build())
|
||||||
.setRegistryLockPassword("hi")
|
.setRegistryLockPassword("hi")
|
||||||
.build();
|
.build();
|
||||||
AuthResult consoleAuthResult =
|
AuthResult consoleAuthResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
|
||||||
action = createAction(consoleAuthResult);
|
action = createAction(consoleAuthResult);
|
||||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||||
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
||||||
|
@ -253,8 +243,7 @@ final class RegistryLockPostActionTest {
|
||||||
.setEmailAddress("johndoe@theregistrar.com")
|
.setEmailAddress("johndoe@theregistrar.com")
|
||||||
.setUserRoles(new UserRoles.Builder().setIsAdmin(true).build())
|
.setUserRoles(new UserRoles.Builder().setIsAdmin(true).build())
|
||||||
.build();
|
.build();
|
||||||
AuthResult consoleAuthResult =
|
AuthResult consoleAuthResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
|
||||||
action = createAction(consoleAuthResult);
|
action = createAction(consoleAuthResult);
|
||||||
Map<String, Object> requestMapWithoutPassword =
|
Map<String, Object> requestMapWithoutPassword =
|
||||||
ImmutableMap.of(
|
ImmutableMap.of(
|
||||||
|
@ -286,7 +275,7 @@ final class RegistryLockPostActionTest {
|
||||||
@Test
|
@Test
|
||||||
void testFailure_unauthorizedRegistrarId() {
|
void testFailure_unauthorizedRegistrarId() {
|
||||||
AuthResult authResult =
|
AuthResult authResult =
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false));
|
AuthResult.createUser(UserAuthInfo.create(userWithLockPermission, false));
|
||||||
action = createAction(authResult, ImmutableSet.of("TheRegistrar"));
|
action = createAction(authResult, ImmutableSet.of("TheRegistrar"));
|
||||||
Map<String, ?> response =
|
Map<String, ?> response =
|
||||||
action.handleJsonRequest(
|
action.handleJsonRequest(
|
||||||
|
@ -358,9 +347,7 @@ final class RegistryLockPostActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFailure_notEnabledForRegistrarPoc() {
|
void testFailure_notEnabledForRegistrarPoc() {
|
||||||
action =
|
action = createAction(AuthResult.createUser(UserAuthInfo.create(userWithoutPermission, false)));
|
||||||
createAction(
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, false)));
|
|
||||||
Map<String, ?> response =
|
Map<String, ?> response =
|
||||||
action.handleJsonRequest(
|
action.handleJsonRequest(
|
||||||
ImmutableMap.of(
|
ImmutableMap.of(
|
||||||
|
@ -453,8 +440,7 @@ final class RegistryLockPostActionTest {
|
||||||
.build())
|
.build())
|
||||||
.setRegistryLockPassword("hi")
|
.setRegistryLockPassword("hi")
|
||||||
.build();
|
.build();
|
||||||
AuthResult consoleAuthResult =
|
AuthResult consoleAuthResult = AuthResult.createUser(UserAuthInfo.create(consoleUser));
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(consoleUser));
|
|
||||||
action = createAction(consoleAuthResult);
|
action = createAction(consoleAuthResult);
|
||||||
Map<String, ?> response =
|
Map<String, ?> response =
|
||||||
action.handleJsonRequest(
|
action.handleJsonRequest(
|
||||||
|
|
|
@ -43,7 +43,6 @@ import google.registry.model.tld.Tld;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.security.XsrfTokenManager;
|
import google.registry.security.XsrfTokenManager;
|
||||||
import google.registry.testing.CloudTasksHelper;
|
import google.registry.testing.CloudTasksHelper;
|
||||||
|
@ -132,7 +131,7 @@ final class RegistryLockVerifyActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_adminLock_createsOnlyHistoryEntry() {
|
void testSuccess_adminLock_createsOnlyHistoryEntry() {
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, true));
|
action.authResult = AuthResult.createUser(UserAuthInfo.create(user, true));
|
||||||
saveRegistryLock(createLock().asBuilder().isSuperuser(true).build());
|
saveRegistryLock(createLock().asBuilder().isSuperuser(true).build());
|
||||||
|
|
||||||
action.run();
|
action.run();
|
||||||
|
@ -332,7 +331,7 @@ final class RegistryLockVerifyActionTest {
|
||||||
stringGenerator, "adminreg", cloudTasksHelper.getTestCloudTasksUtils()),
|
stringGenerator, "adminreg", cloudTasksHelper.getTestCloudTasksUtils()),
|
||||||
lockVerificationCode,
|
lockVerificationCode,
|
||||||
isLock);
|
isLock);
|
||||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
authResult = AuthResult.createUser(UserAuthInfo.create(user, false));
|
||||||
action.req = request;
|
action.req = request;
|
||||||
action.response = response;
|
action.response = response;
|
||||||
action.authResult = authResult;
|
action.authResult = authResult;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
||||||
/_dr/epp EppTlsAction POST n API APP PUBLIC
|
/_dr/epp EppTlsAction POST n API APP ADMIN
|
||||||
/console-api/domain ConsoleDomainGetAction GET n API,LEGACY USER PUBLIC
|
/console-api/domain ConsoleDomainGetAction GET n API,LEGACY USER PUBLIC
|
||||||
/console-api/registrars RegistrarsAction GET,POST n API,LEGACY USER PUBLIC
|
/console-api/registrars RegistrarsAction GET,POST n API,LEGACY USER PUBLIC
|
||||||
/console-api/settings/contacts ContactAction GET,POST n API,LEGACY USER PUBLIC
|
/console-api/settings/contacts ContactAction GET,POST n API,LEGACY USER PUBLIC
|
||||||
|
@ -13,4 +13,4 @@ PATH CLASS METHODS OK AUT
|
||||||
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
|
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
|
||||||
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
|
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
|
||||||
/registry-lock-post RegistryLockPostAction POST n API,LEGACY USER PUBLIC
|
/registry-lock-post RegistryLockPostAction POST n API,LEGACY USER PUBLIC
|
||||||
/registry-lock-verify RegistryLockVerifyAction GET n API,LEGACY NONE PUBLIC
|
/registry-lock-verify RegistryLockVerifyAction GET n API,LEGACY NONE PUBLIC
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
||||||
/_dr/whois WhoisAction POST n API APP PUBLIC
|
/_dr/whois WhoisAction POST n API APP ADMIN
|
||||||
/check CheckApiAction GET n API,LEGACY NONE PUBLIC
|
/check CheckApiAction GET n API,LEGACY NONE PUBLIC
|
||||||
/rdap/autnum/(*) RdapAutnumAction GET,HEAD n API,LEGACY NONE PUBLIC
|
/rdap/autnum/(*) RdapAutnumAction GET,HEAD n API,LEGACY NONE PUBLIC
|
||||||
/rdap/domain/(*) RdapDomainAction GET,HEAD n API,LEGACY NONE PUBLIC
|
/rdap/domain/(*) RdapDomainAction GET,HEAD n API,LEGACY NONE PUBLIC
|
||||||
|
|
|
@ -88,8 +88,7 @@ gSuite:
|
||||||
|
|
||||||
For fully-featured production environments that need the full range of features
|
For fully-featured production environments that need the full range of features
|
||||||
(e.g. RDE, correct contact information on the registrar console, etc.) you will
|
(e.g. RDE, correct contact information on the registrar console, etc.) you will
|
||||||
need to specify more settings. The `nomulus-config-production-sample.yaml` file
|
need to specify more settings.
|
||||||
contains an exhaustive list of all settings to override.
|
|
||||||
|
|
||||||
From a code perspective, all configuration settings ultimately come through the
|
From a code perspective, all configuration settings ultimately come through the
|
||||||
[`RegistryConfig`][registry-config] class. This includes a Dagger module called
|
[`RegistryConfig`][registry-config] class. This includes a Dagger module called
|
||||||
|
|
|
@ -134,16 +134,16 @@ takes a couple of minutes.
|
||||||
### Setup Nomulus
|
### Setup Nomulus
|
||||||
|
|
||||||
After terraform completes, it outputs some information, among which is the
|
After terraform completes, it outputs some information, among which is the
|
||||||
client id of the service account created for the proxy. This needs to be added
|
email address of the service account created for the proxy. This needs to be
|
||||||
to the Nomulus configuration file so that Nomulus accepts traffic from the
|
added to the Nomulus configuration file so that Nomulus accepts traffic from the
|
||||||
proxy. Edit the following section in
|
proxy. Edit the following section in
|
||||||
`java/google/registry/config/files/nomulus-config-<env>.yaml` and redeploy
|
`java/google/registry/config/files/nomulus-config-<env>.yaml` and redeploy
|
||||||
Nomulus:
|
Nomulus:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
oAuth:
|
auth:
|
||||||
allowedOauthClientIds:
|
allowedServiceAccountEmails:
|
||||||
- <client_id>
|
- <email address>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup nameservers
|
### Setup nameservers
|
||||||
|
@ -304,15 +304,15 @@ $ gcloud iam service-accounts keys create proxy-key.json --iam-account \
|
||||||
|
|
||||||
A `proxy-key.json` file will be created inside the current working directory.
|
A `proxy-key.json` file will be created inside the current working directory.
|
||||||
|
|
||||||
The `client_id` inside the key file needs to be added to the Nomulus
|
The service account email address needs to be added to the Nomulus
|
||||||
configuration file so that Nomulus accepts the OAuth tokens generated for this
|
configuration file so that Nomulus accepts the OAuth tokens generated for this
|
||||||
service account. Add its value to
|
service account. Add its value to
|
||||||
`java/google/registry/config/files/nomulus-config-<env>.yaml`:
|
`java/google/registry/config/files/nomulus-config-<env>.yaml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
oAuth:
|
auth:
|
||||||
allowedOauthClientIds:
|
allowedServiceAccountEmails:
|
||||||
- <client_id>
|
- <email address>
|
||||||
```
|
```
|
||||||
|
|
||||||
Redeploy Nomulus for the change to take effect.
|
Redeploy Nomulus for the change to take effect.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue