org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.sling.auth.xing.oauth.impl;

import java.io.IOException;
import java.util.Dictionary;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.PropertyUnbounded;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
import org.apache.sling.auth.xing.api.XingUser;
import org.apache.sling.auth.xing.api.users.Users;
import org.apache.sling.auth.xing.oauth.XingOauth;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.Constants;
import org.osgi.service.component.ComponentContext;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.XingApi;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(label = "Apache Sling Authentication XING OAuth Authentication Handler?", description = "Authentication Handler for Sling Authentication XING OAuth", immediate = true, metatype = true)
@Service
@Properties({ @Property(name = Constants.SERVICE_VENDOR, value = XingOauth.SERVICE_VENDOR),
        @Property(name = Constants.SERVICE_DESCRIPTION, value = "Authentication Handler for Sling Authentication XING OAuth"),
        @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false),
        @Property(name = AuthenticationHandler.PATH_PROPERTY, value = "/", unbounded = PropertyUnbounded.ARRAY),
        @Property(name = AuthenticationHandler.TYPE_PROPERTY, value = XingOauth.AUTH_TYPE, propertyPrivate = true) })
public class XingOauthAuthenticationHandler extends DefaultAuthenticationFeedbackHandler
        implements AuthenticationHandler {

    private OAuthService oAuthService;

    private String consumerKey;

    private String consumerSecret;

    private String callbackUrl;

    private String usersMeUrl;

    private static final String DEFAULT_USERS_ME_URL = "https://api.xing.com/v1/users/me.json";

    @Property(value = "")
    private static final String CONSUMER_KEY_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerKey";

    @Property(value = "")
    private static final String CONSUMER_SECRET_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerSecret";

    @Property(value = "")
    private static final String CALLBACK_URL_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.callbackUrl";

    @Property(value = DEFAULT_USERS_ME_URL)
    private static final String USERS_ME_URL_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.usersMeUrl";

    public static final String USER_SESSION_ATTRIBUTE_NAME = "xing-user";

    private final Logger logger = LoggerFactory.getLogger(XingOauthAuthenticationHandler.class);

    public XingOauthAuthenticationHandler() {
    }

    @Activate
    protected void activate(final ComponentContext componentContext) {
        logger.debug("activate");
        configure(componentContext);
    }

    @Modified
    protected void modified(final ComponentContext componentContext) {
        logger.debug("modified");
        configure(componentContext);
    }

    @Deactivate
    protected void deactivate(final ComponentContext componentContext) {
        logger.debug("deactivate");
    }

    protected synchronized void configure(final ComponentContext componentContext) {
        final Dictionary properties = componentContext.getProperties();
        consumerKey = PropertiesUtil.toString(properties.get(CONSUMER_KEY_PARAMETER), "").trim();
        consumerSecret = PropertiesUtil.toString(properties.get(CONSUMER_SECRET_PARAMETER), "").trim();
        callbackUrl = PropertiesUtil.toString(properties.get(CALLBACK_URL_PARAMETER), "").trim();
        usersMeUrl = PropertiesUtil.toString(properties.get(USERS_ME_URL_PARAMETER), DEFAULT_USERS_ME_URL).trim();

        if (StringUtils.isEmpty(consumerKey)) {
            logger.warn("configured consumer key is empty");
        }

        if (StringUtils.isEmpty(consumerSecret)) {
            logger.warn("configured consumer secret is empty");
        }

        if (StringUtils.isEmpty(callbackUrl)) {
            logger.warn("configured callback URL is empty");
        }

        if (StringUtils.isEmpty(usersMeUrl)) {
            logger.warn("configured users me URL is empty");
        }

        if (!StringUtils.isEmpty(consumerKey) && !StringUtils.isEmpty(consumerSecret)
                && !StringUtils.isEmpty(callbackUrl)) {
            oAuthService = new ServiceBuilder().provider(XingApi.class).apiKey(consumerKey)
                    .apiSecret(consumerSecret).callback(callbackUrl).build();
        } else {
            oAuthService = null;
        }

        logger.info("configured with consumer key '{}', callback url '{}' and users me url '{}'", consumerKey,
                callbackUrl, usersMeUrl);
    }

    // we need the OAuth access token and the user from XING (/v1/users/me)
    @Override
    public AuthenticationInfo extractCredentials(final HttpServletRequest request,
            final HttpServletResponse response) {
        logger.debug("extract credentials");

        if (oAuthService == null) {
            logger.error("OAuthService is null, check configuration");
            return null;
        }

        try {
            final HttpSession httpSession = request.getSession(true);

            Token accessToken = (Token) httpSession.getAttribute(OAuthConstants.ACCESS_TOKEN);
            XingUser xingUser = (XingUser) httpSession.getAttribute(USER_SESSION_ATTRIBUTE_NAME);

            if (accessToken == null) {
                // we need the request token and verifier to get an access token
                final Token requestToken = (Token) httpSession.getAttribute(OAuthConstants.TOKEN);
                final String verifier = request.getParameter(OAuthConstants.VERIFIER);
                if (requestToken == null || verifier == null) {
                    return null;
                }
                accessToken = oAuthService.getAccessToken(requestToken, new Verifier(verifier));
                logger.debug("access token: {}", accessToken);
                httpSession.setAttribute(OAuthConstants.ACCESS_TOKEN, accessToken);
            }

            if (xingUser == null) {
                xingUser = fetchUser(accessToken);
                logger.debug("xing user: {}", xingUser);
                httpSession.setAttribute(USER_SESSION_ATTRIBUTE_NAME, xingUser);
            }

            final AuthenticationInfo authenticationInfo = new AuthenticationInfo(XingOauth.AUTH_TYPE,
                    xingUser.getId());
            authenticationInfo.put(XingOauth.AUTHENTICATION_CREDENTIALS_ACCESS_TOKEN_KEY, accessToken);
            authenticationInfo.put(XingOauth.AUTHENTICATION_CREDENTIALS_USER_KEY, xingUser);
            return authenticationInfo;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            removeAuthFromSession(request);
            return null;
        }
    }

    @Override
    public boolean requestCredentials(final HttpServletRequest request, final HttpServletResponse response)
            throws IOException {
        logger.debug("request credentials");

        if (oAuthService == null) {
            logger.error("OAuthService is null, check configuration");
            return false;
        }

        try {
            final Token requestToken = oAuthService.getRequestToken();
            logger.debug("received request token: '{}'", requestToken);
            final HttpSession httpSession = request.getSession(true);
            httpSession.setAttribute(OAuthConstants.TOKEN, requestToken);
            final String authUrl = oAuthService.getAuthorizationUrl(requestToken);
            logger.debug("redirecting to auth url: '{}'", authUrl);
            response.sendRedirect(authUrl);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void dropCredentials(final HttpServletRequest request, final HttpServletResponse response)
            throws IOException {
        logger.debug("drop credentials");
        removeAuthFromSession(request);
    }

    protected XingUser fetchUser(final Token accessToken) throws Exception {
        final OAuthRequest request = new OAuthRequest(Verb.GET, usersMeUrl);
        oAuthService.signRequest(accessToken, request);
        final Response response = request.send();
        final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .create();
        final Users users = gson.fromJson(response.getBody(), Users.class);
        return users.getUsers().get(0);
    }

    protected void removeAuthFromSession(final HttpServletRequest request) {
        try {
            final HttpSession httpSession = request.getSession();
            httpSession.removeAttribute(OAuthConstants.TOKEN);
            httpSession.removeAttribute(OAuthConstants.ACCESS_TOKEN);
            httpSession.removeAttribute(USER_SESSION_ATTRIBUTE_NAME);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

}