Package org.structr.web.auth

Source Code of org.structr.web.auth.StructrOAuthClient

/**
* Copyright (C) 2010-2014 Morgner UG (haftungsbeschränkt)
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.web.auth;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.GitHubTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthAuthzResponse;
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.utils.JSONUtils;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.Person;
import org.structr.core.property.PropertyKey;

/**
* Central class for OAuth client implementations.
*
* @author Axel Morgner
*/
public class StructrOAuthClient {
 
  private static final Logger logger = Logger.getLogger(StructrOAuthClient.class.getName());
 
  protected enum ResponseFormat {
    json, urlEncoded
  }
 
  private static final String CONFIGURED_OAUTH_SERVERS = "oauth.servers";
 
  protected String authorizationLocation;
  protected String tokenLocation;
  protected String clientId;
  protected String clientSecret;
  protected String redirectUri;
  protected String state;
 
  protected Class tokenResponseClass;
 
  private OAuthAccessTokenResponse tokenResponse;
  private OAuthResourceResponse userResponse;
 
  public StructrOAuthClient() {};
 
  public StructrOAuthClient(final String authorizationLocation, final String tokenLocation, final String clientId, final String clientSecret, final String redirectUri) {
   
    this.init(authorizationLocation, tokenLocation, clientId, clientSecret, redirectUri, OAuthJSONAccessTokenResponse.class);
  }
 
  protected void init(final String authorizationLocation, final String tokenLocation, final String clientId, final String clientSecret, final String redirectUri, final Class tokenResponseClass) {

    this.authorizationLocation = authorizationLocation;
    this.tokenLocation         = tokenLocation;
    this.clientId              = clientId;
    this.clientSecret          = clientSecret;
    this.redirectUri           = redirectUri;
   
    this.tokenResponseClass    = tokenResponseClass;
   
  }
 
  @Override
  public String toString() {
   
    return this.getClass().getName()
    + "\nauthorizationLocation: " + authorizationLocation
    + "\ntokenLocation: " + tokenLocation
    + "\nclientId: " + clientId
    + "\nclientSecret: " + clientSecret
    + "\nredirectUri: " + redirectUri
    + "\nstate: " + state;

  }
 
  /**
   * Create an end-user authorization request
   *
   * Use with {@literal response.setRedirect(request.getLocationUri());}
   *
   * @param request
   * @return request URI
   */
  public String getEndUserAuthorizationRequestUri(final HttpServletRequest request) {
   
    OAuthClientRequest oauthClientRequest;
   
    try {
     
      oauthClientRequest = OAuthClientRequest
        .authorizationLocation(authorizationLocation)
        .setClientId(clientId)
        .setRedirectURI(getAbsoluteUrl(request, redirectUri))
        .setScope(getScope())
        .setResponseType(getResponseType())
        .setState(getState())
        .buildQueryMessage();

      logger.log(Level.INFO, "Authorization request location URI: {0}", oauthClientRequest.getLocationUri());
   
      return oauthClientRequest.getLocationUri();
     
    } catch (OAuthSystemException ex) {
      logger.log(Level.SEVERE, null, ex);
    }
   
    return null;
   
  }
 
  /**
   * Build an OAuth2 server from the configured values for the given name.
   *
   * @param name
   * @return server
   */
  public static StructrOAuthClient getServer(final String name) {

    String configuredOauthServers  = StructrApp.getConfigurationValue(CONFIGURED_OAUTH_SERVERS, "twitter facebook google github stackoverflow");
    String[] authServers = configuredOauthServers.split(" ");

    for (String authServer : authServers) {
     
      if (authServer.equals(name)) {
     
        String authLocation  = StructrApp.getConfigurationValue("oauth." + authServer + ".authorization_location", null);
        String tokenLocation = StructrApp.getConfigurationValue("oauth." + authServer + ".token_location", null);
        String clientId      = StructrApp.getConfigurationValue("oauth." + authServer + ".client_id", null);
        String clientSecret  = StructrApp.getConfigurationValue("oauth." + authServer + ".client_secret", null);
        String redirectUri   = StructrApp.getConfigurationValue("oauth." + authServer + ".redirect_uri", null);

        // Minumum required fields
        if (clientId != null && clientSecret != null && redirectUri != null) {

          Class serverClass    = getServerClassForName(name);
          Class tokenResponseClass  = getTokenResponseClassForName(name);
         
          StructrOAuthClient oauthServer;
          try {
           
            oauthServer = (StructrOAuthClient) serverClass.newInstance();
            oauthServer.init(authLocation, tokenLocation, clientId, clientSecret, redirectUri, tokenResponseClass);
           
            logger.log(Level.INFO, "Using OAuth server {0}", oauthServer);
           
            return oauthServer;
 
          } catch (Throwable t) {
           
            logger.log(Level.SEVERE, "Could not instantiate auth server", t);
           
          }


        }
       
      }

    }
       
    return null;
  }

  private static Class getTokenResponseClassForName(final String name) {

    // The following comments are taken from https://cwiki.apache.org/confluence/display/OLTU/OAuth+2.0+Client+Quickstart
   
    // "Facebook is not fully compatible with OAuth 2.0 draft 10, access token response is
    // application/x-www-form-urlencoded, not json encoded so we use dedicated response class for that
    // Custom response classes are an easy way to deal with oauth providers that introduce modifications to
    // OAuth 2.0 specification"
   
    switch (name) {
     
      case "github" :
        return GitHubTokenResponse.class;
      case "facebook" :
        return GitHubTokenResponse.class;
      default :
        return OAuthJSONAccessTokenResponse.class;
    }
   
  }

  private static Class getServerClassForName(final String name) {
 
    switch (name) {
     
      case "github" :
        return GitHubAuthClient.class;
      case "twitter" :
        return TwitterAuthClient.class;
      case "facebook" :
        return FacebookAuthClient.class;
      case "linkedin" :
        return LinkedInAuthClient.class;
      case "google" :
        return GoogleAuthClient.class;
      default :
        return StructrOAuthClient.class;
    }
   
  }

  protected GrantType getGrantType() {
    return GrantType.AUTHORIZATION_CODE;
  }
 
  protected String getScope() {
    return "";
  }
 
  protected String getResponseType() {
    return "code";
  }

  protected String getState() {
    return "";
  }

  protected String getAccessTokenParameterKey() {
    return OAuth.OAUTH_BEARER_TOKEN;
  }
 
  private static String getCode(final HttpServletRequest request) {
   
    OAuthAuthzResponse oar;

    try {

      logger.log(Level.INFO, "Trying to get authorization code from request {0}", request);
     
      oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
     
      String code = oar.getCode();
     
      logger.log(Level.INFO, "Got code {0} from authorization request", code);
     
      return oar.getCode();

    } catch (OAuthProblemException e) {

      logger.log(Level.SEVERE, "Could not read authorization request: {0}, {1}", new Object[] { e.getError(), e.getDescription() });

    }
   
    return null;
   
   
  }

  public PropertyKey getCredentialKey() {
   
    return Person.eMail;
   
  }
 
  public String getCredential(final HttpServletRequest request) {
   
    return getValue(request, "email");
   
  }
 
  public String getValue(final HttpServletRequest request, final String key) {
   
    try {
     
      OAuthResourceResponse userResponse = getUserResponse(request);

      if (userResponse == null) {

        return null;

      }

      String body = userResponse.getBody();
 
      logger.log(Level.INFO, "User response body: {0}", body);
      return (String) JSONUtils.parseJSON(body).get(key);
     
    } catch (Exception ex) {
     
      logger.log(Level.WARNING, "Could not extract {0} from JSON response", ex);
     
    }
   
    return null;
   
  }

  public String getAccessToken(final HttpServletRequest request) {
   
    OAuthAccessTokenResponse resp = getAccessTokenResponse(request);
   
    if (resp == null) {
      return null;
    }
   
    return resp.getAccessToken();
     
  }
 
  public Long getExpiresIn(final HttpServletRequest request) {
   
    OAuthAccessTokenResponse resp = getAccessTokenResponse(request);
   
    if (resp == null) {
      return null;
    }
   
    return resp.getExpiresIn();
   
  }
 
  private OAuthAccessTokenResponse getAccessTokenResponse(final HttpServletRequest request) {
   
    if (tokenResponse != null) {
     
      return tokenResponse;
     
    }
   
    try {
   
      String code = getCode(request);
     
      if (code == null) {
       
        logger.log(Level.SEVERE, "Could not get code from request, cancelling authorization process");
        return null;
       
      }
     
      OAuthClientRequest clientReq = OAuthClientRequest
        .tokenLocation(tokenLocation)
        .setGrantType(getGrantType())
        .setClientId(clientId)
        .setClientSecret(clientSecret)
        .setRedirectURI(getAbsoluteUrl(request, redirectUri))
        .setCode(getCode(request))
      .buildBodyMessage();

      logger.log(Level.INFO, "Request body: {0}", clientReq.getBody());

      OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

      tokenResponse = oAuthClient.accessToken(clientReq, tokenResponseClass);
     
      logger.log(Level.INFO, "Access token response: {0}", tokenResponse.getBody());
     
      return tokenResponse;
     
    } catch (Throwable t) {
     
      logger.log(Level.SEVERE, "Could not get access token response", t);
     
    }
   
    return null;
   
  }

  /**
   * Where to fetch user information from the auth server
   *
   * @return resource URI
   */
  public String getUserResourceUri() {
   
    return "";
   
  }
 
  /**
   * Path to redirect to on success
   * @return return URI
   */
  public String getReturnUri() {
   
    return "/";
   
  }
 
  /**
   * Path to redirect to on error
   *
   * @return error URI
   */
  public String getErrorUri() {
   
    return "/";
   
  }

  protected OAuthResourceResponse getUserResponse(final HttpServletRequest request) {
   
    if (userResponse != null) {
     
      return userResponse;
     
    }
   
    try {
   
      String accessToken = getAccessToken(request);
     
      if (accessToken != null) {
       
        final String accessTokenParameterKey = this.getAccessTokenParameterKey();
       
        OAuthClientRequest clientReq = new OAuthBearerClientRequest(getUserResourceUri()) {
       
          @Override
          public OAuthBearerClientRequest setAccessToken(String accessToken) {
              this.parameters.put(accessTokenParameterKey, accessToken);
              return this;
          }
       
        }
          .setAccessToken(accessToken)
          .buildQueryMessage();
       
        // needed for LinkedIn
        clientReq.setHeader("x-li-format", "json");
       
        logger.log(Level.INFO, "User info request: {0}", clientReq.getLocationUri());
       
        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

        userResponse = oAuthClient.resource(clientReq, "GET", OAuthResourceResponse.class);
        logger.log(Level.INFO, "User info response: {0}", userResponse);

        return userResponse;
       
      }
     
    } catch (Throwable t) {
     
      logger.log(Level.SEVERE, "Could not get user response", t);
     
    }
   
    return null;
   
  }
   
  protected String getAbsoluteUrl(final HttpServletRequest request, final String redirectUri) {
   
    return !(redirectUri.startsWith("http")) ? "http" + (request.isSecure() ? "s" : "") + "://" + request.getServerName() + ":" + request.getServerPort() + redirectUri : redirectUri;
   
  }
 
  public ResponseFormat getResponseFormat() {
   
    return ResponseFormat.json;
   
  }
 
}
TOP

Related Classes of org.structr.web.auth.StructrOAuthClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.