// Copyright 2018 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.ui.server.registrar; import static google.registry.model.ofy.ObjectifyService.ofy; import com.google.appengine.api.users.User; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.flogger.FluentLogger; import google.registry.config.RegistryConfig.Config; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarContact; import google.registry.request.HttpException.ForbiddenException; import google.registry.request.auth.AuthResult; import google.registry.request.auth.UserAuthInfo; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; /** * Allows access only to {@link Registrar}s the current user has access to. * *
A user has OWNER role on a Registrar if there exists a {@link RegistrarContact} with * that user's gaeId and the registrar as a parent. * *
An admin has in addition OWNER role on {@link #registryAdminClientId}. * *
An admin also has ADMIN role on ALL registrars. */ @Immutable public class AuthenticatedRegistrarAccessor { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); /** The role under which access is granted. */ public enum Role { OWNER, ADMIN } AuthResult authResult; String registryAdminClientId; /** * Gives all roles a user has for a given clientId. * *
The order is significant, with "more specific to this user" coming first.
*/
private final ImmutableSetMultimap Throws a {@link ForbiddenException} if the user is not logged in.
*
* The result is ordered starting from "most specific to this user".
*
* If you want to load the {@link Registrar} object from these (or any other) {@code clientId},
* in order to perform actions on behalf of a user, you must use {@link #getRegistrar} which makes
* sure the user has permissions.
*
* Note that this is an OPTIONAL step in the authentication - only used if we don't have any
* other clue as to the requested {@code clientId}. It is perfectly OK to get a {@code clientId}
* from any other source, as long as the registrar is then loaded using {@link #getRegistrar}.
*/
public ImmutableSetMultimap If no such ClientIds exist, throws a ForbiddenException.
*
* This should be the ClientId "most likely wanted by the user".
*
* If you want to load the {@link Registrar} object from this (or any other) {@code clientId},
* in order to perform actions on behalf of a user, you must use {@link #getRegistrar} which makes
* sure the user has permissions.
*
* Note that this is an OPTIONAL step in the authentication - only used if we don't have any
* other clue as to the requested {@code clientId}. It is perfectly OK to get a {@code clientId}
* from any other source, as long as the registrar is then loaded using {@link #getRegistrar}.
*/
public String guessClientId() {
verifyLoggedIn();
return getAllClientIdWithRoles().keySet().stream()
.findFirst()
.orElseThrow(
() ->
new ForbiddenException(
String.format(
"%s isn't associated with any registrar",
authResult.userIdForLogging())));
}
/**
* Loads a Registrar IFF the user is authorized.
*
* Throws a {@link ForbiddenException} if the user is not logged in, or not authorized to
* access the requested registrar.
*
* @param clientId ID of the registrar we request
*/
public Registrar getRegistrar(String clientId) {
verifyLoggedIn();
ImmutableSet