Package org.expressme.openid

Source Code of org.expressme.openid.OpenIdManager

package org.expressme.openid;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;

/**
* Open ID Manager for all open id operation.
*
* @author Michael Liao (askxuefeng@gmail.com)
* @author Erwin Quinto (erwin.quinto@gmail.com)
*/
public class OpenIdManager {

    private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

    private ShortName shortName = new ShortName();
    private Map<String, Endpoint> endpointCache = new ConcurrentHashMap<String, Endpoint>();
    private Map<Endpoint, Association> associationCache = new ConcurrentHashMap<Endpoint, Association>();

    private int timeOut = 5000; // 5 seconds
    private String assocQuery = null;
    private String authQuery = null;
    private String returnTo = null;
    private String returnToUrlEncode = null;
    private String realm = null;

    /**
     * Set returning address after authentication.
     *
     * @param returnTo URL that should redirect to.
     */
    public void setReturnTo(String returnTo) {
        try {
            this.returnToUrlEncode = Utils.urlEncode(returnTo);
        }
        catch(UnsupportedEncodingException e) {
            throw new OpenIdException(e);
        }
        this.returnTo = returnTo;
    }

    /**
     * Set realm. For example, "http://*.example.com".
     *
     * @param realm Realm of RP.
     */
    public void setRealm(String realm) {
        try {
            this.realm = Utils.urlEncode(realm);
        }
        catch(UnsupportedEncodingException e) {
            throw new OpenIdException(e);
        }
    }

    /**
     * Set timeout in milliseconds.
     */
    public void setTimeOut(int timeOutInMilliseconds) {
        this.timeOut = timeOutInMilliseconds;
    }

    /**
     * Get authentication information from HTTP request and key.
     * @deprecated Using getAuthentication(HttpServletRequest request, byte[] key, String alias) instead.
     */
    public Authentication getAuthentication(HttpServletRequest request, byte[] key) {
      return getAuthentication(request, key, Endpoint.DEFAULT_ALIAS);
    }

    /**
     * Get authentication information from HTTP request, key.and alias
     */
    public Authentication getAuthentication(HttpServletRequest request, byte[] key, String alias) {
        // verify:
        String identity = request.getParameter("openid.identity");
        if (identity==null)
            throw new OpenIdException("Missing 'openid.identity'.");
        if (request.getParameter("openid.invalidate_handle")!=null)
            throw new OpenIdException("Invalidate handle.");
        String sig = request.getParameter("openid.sig");
        if (sig==null)
            throw new OpenIdException("Missing 'openid.sig'.");
        String signed = request.getParameter("openid.signed");
        if (signed==null)
            throw new OpenIdException("Missing 'openid.signed'.");
        if (!returnTo.equals(request.getParameter("openid.return_to")))
            throw new OpenIdException("Bad 'openid.return_to'.");
        // check sig:
        String[] params = signed.split("[\\,]+");
        StringBuilder sb = new StringBuilder(1024);
        for (String param : params) {
            sb.append(param)
              .append(':');
            String value = request.getParameter("openid." + param);
            if (value!=null)
                sb.append(value);
            sb.append('\n');
        }
        String hmac = getHmacSha1(sb.toString(), key);
        if (!safeEquals(sig, hmac))
            throw new OpenIdException("Verify signature failed.");

        // set auth:
        Authentication auth = new Authentication();
        auth.setIdentity(identity);
        auth.setEmail(request.getParameter("openid." + alias + ".value.email"));
        auth.setLanguage(request.getParameter("openid." + alias + ".value.language"));
        auth.setGender(request.getParameter("openid." + alias + ".value.gender"));
        auth.setFullname(getFullname(request, alias));
        auth.setFirstname(getFirstname(request, alias));
        auth.setLastname(getLastname(request, alias));
        return auth;
    }

    boolean safeEquals(String s1, String s2) {
        if (s1.length()!=s2.length())
            return false;
        int result = 0;
        for (int i=0; i<s1.length(); i++) {
            int c1 = s1.charAt(i);
            int c2 = s2.charAt(i);
            result |= (c1 ^c2);
        }
        return result==0;
    }

    String getLastname (HttpServletRequest request, String axa) {
      String name = request.getParameter("openid." + axa + ".value.lastname");
      // If lastname is not supported try to get it from the fullname
      if (name == null) {
        name = request.getParameter("openid." + axa + ".value.fullname");
        if (name != null) {
            int n = name.lastIndexOf(' ');
            if (n!=(-1))
                name = name.substring(n + 1);
        }
      }
      return name;
    }

    String getFirstname(HttpServletRequest request, String axa) {
      String name = request.getParameter("openid." + axa + ".value.firstname");
      //If firstname is not supported try to get it from the fullname
      if (name == null) {
        name = request.getParameter("openid." + axa + ".value.fullname");
        if (name != null) {
            int n = name.indexOf(' ');
                if (n!=(-1))
                    name = name.substring(0, n);
        }
      }
      return name;
    }

    String getFullname(HttpServletRequest request, String axa) {
      // If fullname is not supported then get combined first and last name
      String fname = request.getParameter("openid."+axa+".value.fullname");
      if (fname == null) {
        fname = request.getParameter("openid."+axa+".value.firstname");
        if (fname != null) {
          fname += " ";
        }
        fname += request.getParameter("openid."+axa+".value.lastname");
      }
      return fname;
    }

    String getHmacSha1(String data, byte[] key) {
        SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1_ALGORITHM);
        Mac mac = null;
        try {
            mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
            mac.init(signingKey);
        }
        catch(NoSuchAlgorithmException e) {
            throw new OpenIdException(e);
        }
        catch(InvalidKeyException e) {
            throw new OpenIdException(e);
        }
        try {
            byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
            return Base64.encodeBytes(rawHmac);
        }
        catch(IllegalStateException e) {
            throw new OpenIdException(e);
        }
        catch(UnsupportedEncodingException e) {
            throw new OpenIdException(e);
        }
    }

    /**
     * Lookup end point by name or full URL.
     */
    public Endpoint lookupEndpoint(String nameOrUrl) {
        String url = null;
        String alias = null;
        if (nameOrUrl.startsWith("http://") || nameOrUrl.startsWith("https://"))
            url = nameOrUrl;
        else {
            url = shortName.lookupUrlByName(nameOrUrl);
            if (url==null)
                throw new OpenIdException("Cannot find OP URL by name: " + nameOrUrl);
            alias = shortName.lookupAliasByName(nameOrUrl);
        }
        Endpoint endpoint = endpointCache.get(url);
        if (endpoint!=null && !endpoint.isExpired())
            return endpoint;
        endpoint = requestEndpoint(url, alias==null ? Endpoint.DEFAULT_ALIAS : alias);
        endpointCache.put(url, endpoint);
        return endpoint;
    }

    public Association lookupAssociation(Endpoint endpoint) {
        Association assoc = associationCache.get(endpoint);
        if (assoc!=null && !assoc.isExpired())
            return assoc;
        assoc = requestAssociation(endpoint);
        associationCache.put(endpoint, assoc);
        return assoc;
    }

    public String getAuthenticationUrl(Endpoint endpoint, Association association) {
        StringBuilder sb = new StringBuilder(1024);
        sb.append(endpoint.getUrl())
          .append(endpoint.getUrl().contains("?") ? '&' : '?')
          .append(getAuthQuery(endpoint.getAlias()))
          .append("&openid.return_to=")
          .append(returnToUrlEncode)
          .append("&openid.assoc_handle=")
          .append(association.getAssociationHandle());
        if (realm!=null)
            sb.append("&openid.realm=").append(realm);
        return sb.toString();
    }

    Endpoint requestEndpoint(String url, String alias) {
        Map<String, Object> map = Utils.httpRequest(
                url,
                "GET",
                "application/xrds+xml",
                null,
                timeOut
        );
        try {
            String content = Utils.getContent(map);
            return new Endpoint(Utils.mid(content, "<URI>", "</URI>"), alias, Utils.getMaxAge(map));
        }
        catch(UnsupportedEncodingException e) {
            throw new OpenIdException(e);
        }
    }

    Association requestAssociation(Endpoint endpoint) {
        Map<String, Object> map = Utils.httpRequest(
                endpoint.getUrl(),
                "POST",
                "*/*",
                getAssocQuery(),
                timeOut
        );
        String content = null;
        try {
            content = Utils.getContent(map);
        }
        catch(UnsupportedEncodingException e) {
            throw new OpenIdException(e);
        }
        Association assoc = new Association();
        try {
            BufferedReader r = new BufferedReader(new StringReader(content));
            for (;;) {
                String line = r.readLine();
                if (line==null)
                    break;
                line = line.trim();
                int pos = line.indexOf(':');
                if (pos!=(-1)) {
                    String key = line.substring(0, pos);
                    String value = line.substring(pos + 1);
                    if ("session_type".equals(key))
                        assoc.setSessionType(value);
                    else if ("assoc_type".equals(key))
                        assoc.setAssociationType(value);
                    else if ("assoc_handle".equals(key))
                        assoc.setAssociationHandle(value);
                    else if ("mac_key".equals(key))
                        assoc.setMacKey(value);
                    else if ("expires_in".equals(key)) {
                        long maxAge = Long.parseLong(value);
                        assoc.setMaxAge(maxAge * 900L); // 90%
                    }
                }
            }
        }
        catch(IOException e) {
            throw new RuntimeException("IOException is impossible!", e);
        }
        return assoc;
    }

    String getAuthQuery(String axa) {
        if (authQuery!=null)
            return authQuery;
        List<String> list = new ArrayList<String>();
        list.add("openid.ns=http://specs.openid.net/auth/2.0");
        list.add("openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select");
        list.add("openid.identity=http://specs.openid.net/auth/2.0/identifier_select");
        list.add("openid.mode=checkid_setup");
        list.add("openid.ns." + axa + "=http://openid.net/srv/ax/1.0");
        list.add("openid." + axa + ".mode=fetch_request");
        list.add("openid." + axa + ".type.email=http://axschema.org/contact/email");
        list.add("openid." + axa + ".type.fullname=http://axschema.org/namePerson");
        list.add("openid." + axa + ".type.language=http://axschema.org/pref/language");
        list.add("openid." + axa + ".type.firstname=http://axschema.org/namePerson/first");
        list.add("openid." + axa + ".type.lastname=http://axschema.org/namePerson/last");
        list.add("openid." + axa + ".type.gender=http://axschema.org/person/gender");
        list.add("openid." + axa + ".required=email,fullname,language,firstname,lastname,gender");
        String query = Utils.buildQuery(list);
        authQuery = query;
        return query;
    }

    String getAssocQuery() {
        if (assocQuery!=null)
            return assocQuery;
        List<String> list = new ArrayList<String>();
        list.add("openid.ns=http://specs.openid.net/auth/2.0");
        list.add("openid.mode=associate");
        list.add("openid.session_type=" + Association.SESSION_TYPE_NO_ENCRYPTION);
        list.add("openid.assoc_type=" + Association.ASSOC_TYPE_HMAC_SHA1);
        String query = Utils.buildQuery(list);
        assocQuery = query;
        return query;
    }
}
TOP

Related Classes of org.expressme.openid.OpenIdManager

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.