All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.minijax.gplus.GooglePlusCallback Maven / Gradle / Ivy

package org.minijax.gplus;

import java.io.IOException;
import java.net.URI;
import java.util.UUID;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;

import org.minijax.avatar.AvatarService;
import org.minijax.db.Avatar;
import org.minijax.security.Security;
import org.minijax.security.SecurityDao;
import org.minijax.security.SecurityUser;
import org.minijax.util.IdUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.services.plus.Plus;
import com.google.api.services.plus.model.Person;

/**
 * Handles Google OAuth callback.
 *
 * Based on:
 * https://github.com/google/google-api-java-client-samples
 * plus-preview-appengine-sample/src/main/java/com/google/api/services/samples/plus/PlusSampleAuthCallbackServlet.java
 */
@Path("/googlecallback")
@RequestScoped
public class GooglePlusCallback {
    private static final Logger LOG = LoggerFactory.getLogger(GooglePlusCallback.class);
    private static final URI ERROR_URI = URI.create("/docs/google-error");

    @Inject
    private Security security;

    @Inject
    private SecurityDao dao;

    @Inject
    private AvatarService avatarService;

    @Inject
    private GooglePlusService gplusService;

    @GET
    public Response handleCallback(
            @QueryParam("code") final String code,
            @QueryParam("state") final String state)
                    throws IOException {

        if (code == null) {
            return Response.seeOther(ERROR_URI).build();
        }

        // Note that this implementation does not handle the user denying authorization.
        final GoogleAuthorizationCodeFlow authFlow = gplusService.initializeFlow();

        // Exchange authorization code for user credentials.
        final GoogleTokenResponse tokenResponse = authFlow.newTokenRequest(code)
                .setRedirectUri(gplusService.getRedirectUri().toString())
                .execute();

        final UUID tempId = IdUtils.create();
        final Credential credential = authFlow.createAndStoreCredential(tokenResponse, tempId.toString());
        final Plus plus = gplusService.getPlus(credential);
        final Person person = plus.people().get("me").execute();

        if (person == null || person.getEmails() == null || person.getEmails().isEmpty()) {
            return Response.seeOther(ERROR_URI).build();
        }

        SecurityUser user;
        NewCookie cookie = null;

        if (security.isLoggedIn()) {
            // User is already authenticated
            user = security.getUserPrincipal();

        } else {
            // User is not yet authenticated
            // Need to check if this is a valid user
            final String email = person.getEmails().get(0).getValue();
            user = dao.findUserByEmail(security.getUserClass(), email);
            if (user == null) {
                // This email address is not registered in the database
                // In the future, we may consider auto-creating new user accounts
                // For now, show an error message that we are in private beta.
                LOG.info("Attempted login from \"{}\"", email);
                return Response.seeOther(URI.create("/docs/beta")).build();
            }

            cookie = security.loginAs(user);
        }

        if (user.getAvatar() == null || user.getAvatar().getImageType() == Avatar.IMAGE_TYPE_DEFAULT) {
            tryGooglePlus(user, person);
        }

        ((GooglePlusUser) user).setGoogleCredentials(gplusService.extractUserCredential(tempId));
        dao.update(user);

        final String next = state != null ? state : "/";

        if (cookie != null) {
            return Response.seeOther(URI.create(next)).cookie(cookie).build();
        } else {
            return Response.seeOther(URI.create(next)).build();
        }
    }


    /**
     * Tries to fetch a remote Google Plus profile image.
     *
     * On success, downloads the image, creates thumbnails, uploads to S3, and updates the user object.
     *
     * @param user The user.
     * @param person The Google Plus person.
     * @return True on success; false otherwise.
     */
    private boolean tryGooglePlus(final SecurityUser user, final Person person) throws IOException {
        String url = person.getImage().getUrl();

        // By default, the Google+ profile URL has a "sz=50" query string param
        // Remove that param to get the full size picture
        url = url.replaceAll("\\?sz=\\d+", "");

        return avatarService.tryRemotePicture(user, url, Avatar.IMAGE_TYPE_GOOGLE);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy