google.registry.ui.server.registrar.SessionUtils.java Source code

Java tutorial

Introduction

Here is the source code for google.registry.ui.server.registrar.SessionUtils.java

Source

// Copyright 2016 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 com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static google.registry.model.ofy.ObjectifyService.ofy;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.googlecode.objectify.Key;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.util.FormattingLogger;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/** HTTP session management helper class. */
@Immutable
public class SessionUtils {

    private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();

    public static final String CLIENT_ID_ATTRIBUTE = "clientId";

    private final UserService userService;

    @Inject
    public SessionUtils(UserService userService) {
        this.userService = checkNotNull(userService);
    }

    /**
     * Checks GAE user has access to Registrar Console.
     *
     * <p>This routine will first check the HTTP session (creating one if it doesn't exist) for the
     * {@code clientId} attribute:
     *
     * <ul>
     * <li>If it does not exist, then we will attempt to guess the {@link Registrar} with which the
     * user's GAIA ID is associated. The {@code clientId} of the first matching {@code Registrar} will
     * then be stored to the HTTP session.
     * <li>If it does exist, then we'll fetch the Registrar from the datastore to make sure access
     * wasn't revoked. This should only cost one memcache read.
     * </ul>
     *
     * <p><b>Note:</b> You must ensure the user has logged in before calling this method, for example
     * by setting {@code @Action(requireLogin = true)}.
     *
     * @return {@code false} if user does not have access, in which case the caller should write an
     *     error response and abort the request.
     */
    @CheckReturnValue
    public boolean checkRegistrarConsoleLogin(HttpServletRequest req) {
        HttpSession session = req.getSession();
        User user = userService.getCurrentUser();
        checkState(user != null, "No logged in user found");
        String clientId = (String) session.getAttribute(CLIENT_ID_ATTRIBUTE);
        if (clientId == null) {
            Optional<Registrar> registrar = guessRegistrar(user.getUserId());
            if (!registrar.isPresent()) {
                logger.infofmt("User not associated with any Registrar: %s (%s)", user.getUserId(),
                        user.getEmail());
                return false;
            }
            verify(hasAccessToRegistrar(registrar.get(), user.getUserId()));
            session.setAttribute(CLIENT_ID_ATTRIBUTE, registrar.get().getClientId());
        } else {
            if (!hasAccessToRegistrar(clientId, user.getUserId())) {
                logger.infofmt("Registrar Console access revoked: %s for %s (%s)", clientId, user.getEmail(),
                        user.getUserId());
                session.invalidate();
                return false;
            }
        }
        return true;
    }

    /**
     * Returns {@link Registrar} clientId associated with HTTP session.
     *
     * @throws IllegalStateException if you forgot to call {@link #checkRegistrarConsoleLogin}.
     */
    @CheckReturnValue
    public String getRegistrarClientId(HttpServletRequest req) {
        String clientId = (String) req.getSession().getAttribute(CLIENT_ID_ATTRIBUTE);
        checkState(clientId != null, "You forgot to call checkRegistrarConsoleLogin()");
        return clientId;
    }

    /** @see UserService#isUserLoggedIn() */
    public boolean isLoggedIn() {
        return userService.isUserLoggedIn();
    }

    /** Returns first {@link Registrar} that {@code gaeUserId} is authorized to administer. */
    private static Optional<Registrar> guessRegistrar(String gaeUserId) {
        RegistrarContact contact = ofy().load().type(RegistrarContact.class).filter("gaeUserId", gaeUserId).first()
                .now();
        if (contact == null) {
            return Optional.absent();
        }
        Optional<Registrar> result = Optional.fromNullable(ofy().load().key(contact.getParent()).now());
        if (!result.isPresent()) {
            logger.severefmt("A contact record exists for non-existent registrar: %s.", Key.create(contact));
        }
        return result;
    }

    /** @see #hasAccessToRegistrar(Registrar, String) */
    private static boolean hasAccessToRegistrar(String clientId, final String gaeUserId) {
        Registrar registrar = Registrar.loadByClientId(clientId);
        if (registrar == null) {
            logger.warningfmt("Registrar '%s' disappeared from the datastore!", clientId);
            return false;
        }
        return hasAccessToRegistrar(registrar, gaeUserId);
    }

    /** Returns {@code true} if {@code gaeUserId} is listed in contacts. */
    private static boolean hasAccessToRegistrar(Registrar registrar, final String gaeUserId) {
        return FluentIterable.from(registrar.getContacts()).anyMatch(new Predicate<RegistrarContact>() {
            @Override
            public boolean apply(@Nonnull RegistrarContact contact) {
                return gaeUserId.equals(contact.getGaeUserId());
            }
        });
    }
}