Package org.restlet.ext.openid.internal

Source Code of org.restlet.ext.openid.internal.OpenIdConsumer

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.openid.internal;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONException;
import org.json.JSONObject;
import org.openid4java.OpenIDException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.Discovery;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.AuthSuccess;
import org.openid4java.message.MessageException;
import org.openid4java.message.MessageExtension;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.restlet.data.Cookie;
import org.restlet.data.CookieSetting;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

/**
* OpenID consumer representation implementing an open identity RP.
*
* @author Kristoffer Gronowski
*/
public class OpenIdConsumer extends ServerResource {

    public static final ConcurrentHashMap<String, String> ax = new ConcurrentHashMap<String, String>(
            9);

    public static final String DESCRIPTOR_COOKIE = "openid-disc";

    private static Discovery discovery = new Discovery();

    private static ConcurrentHashMap<String, ConsumerManager> managers = new ConcurrentHashMap<String, ConsumerManager>();

    private static ConcurrentHashMap<String, Object> session = new ConcurrentHashMap<String, Object>();

    static {
        ax.put("nickname", "http://axschema.org/namePerson/friendly");
        ax.put("email", "http://axschema.org/contact/email"); // "http://schema.openid.net/contact/email"
        ax.put("fullname", "http://axschema.org/namePerson");
        ax.put("dob", "http://axschema.org/birthDate");
        ax.put("gender", "http://axschema.org/person/gender");
        ax.put("postcode", "http://axschema.org/contact/postalCode/home");
        ax.put("country", "http://axschema.org/contact/country/home");
        ax.put("language", "http://axschema.org/pref/language");
        ax.put("timezone", "http://axschema.org/pref/timezone");
    }

    // public ConsumerManager manager;
    private Logger log;

    @Override
    protected void doInit() throws ResourceException {
        super.doInit();
        log = getLogger();

        // ConcurrentMap<String,Object> attribs = getContext().getAttributes();
        // manager = (ConsumerManager) attribs.get("consumer_manager");
    }

    /**
     * Returns the representation of an authentication form, in this case, a
     * simple HTML form.
     *
     * @param authReq
     *            The authentication request.
     * @return The representation of an authentication form.
     */
    private Representation generateForm(AuthRequest authReq) {
        StringBuilder sb = new StringBuilder();
        sb.append("<html>");
        sb.append("<head>");
        sb.append("<title>OpenID HTML FORM Redirection</title>");
        sb.append("</head>");
        sb.append("<body onload=\"document.forms['openid-form-redirection'].submit();\">");
        sb.append("<form name=\"openid-form-redirection\" action=\"");
        sb.append(authReq.getOPEndpoint());
        sb.append("\" method=\"post\" accept-charset=\"utf-8\">");
        for (Object key : authReq.getParameterMap().keySet()) {
            sb.append(" <input type=\"hidden\" name=\"");
            sb.append(key.toString());
            // ${parameter.key}
            sb.append("\" value=\"");
            sb.append(authReq.getParameterMap().get(key));
            sb.append("\"/>");
        }
        sb.append("</form>");
        sb.append("</body>");
        sb.append("</html>");
        return new StringRepresentation(sb.toString(), MediaType.TEXT_HTML);
    }

    /**
     * Returns the {@link ConsumerManager} corresponding to the given URI.
     *
     * @param OPUri
     *            The OP endpoint URI.
     * @return The {@link ConsumerManager} corresponding to the given URI.
     */
    private ConsumerManager getManager(String OPUri) {
        log.info("Getting consumer manager for - " + OPUri);
        if (!managers.containsKey(OPUri)) {
            // create a new manager
            log.info("Creating new consumer manager for - " + OPUri);
            try {
                ConsumerManager cm = new ConsumerManager();
                cm.setConnectTimeout(30000);
                cm.setSocketTimeout(30000);
                cm.setFailedAssocExpire(0); // sec 0 = disabled
                // cm.setMaxAssocAttempts(4); //default
                managers.put(OPUri, cm);
                return cm;
            } catch (ConsumerException e) {
                log.warning("Failed to create ConsumerManager for - " + OPUri);
            }
            return null;
        } else {
            return managers.get(OPUri);
        }
    }

    // Used for RP discovery
    @Override
    protected Representation head() throws ResourceException {
        getLogger().info("IN head() OpenIDResource");
        setXRDSHeader();
        getLogger().info("Sending empty representation.");
        return new EmptyRepresentation();
    }

    @Get("html")
    public Representation represent() {
        Form params = getQuery();
        log.info("OpenIDResource : " + params);

        String rc = params.getFirstValue("return");
        if (rc != null && rc.length() > 0) {
            Map<String, String> axRequired = new HashMap<String, String>();
            Map<String, String> axOptional = new HashMap<String, String>();
            Identifier i = verifyResponse(axRequired, axOptional);
            if (i == null) {
                log.info("Authentication Failed");
                getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                return new StringRepresentation("Authentication Failed");
            }
            log.info("Identifier = " + i.getIdentifier());
            String id = i.getIdentifier();
            if (id != null) {
                // New Code, always return JSON and let filter handle any
                // callback.
                // TODO maybe move it to use Principal.
                JSONObject obj = new JSONObject();
                try {
                    obj.put("id", i.getIdentifier());
                    for (String s : axRequired.keySet()) {
                        obj.put(s, axRequired.get(s));
                    }
                    for (String s : axOptional.keySet()) {
                        obj.put(s, axOptional.get(s));
                    }
                } catch (JSONException e) {
                    log.log(Level.WARNING, "Failed to get the ID!", e);
                }

                getResponse().setEntity(new JsonRepresentation(obj));
            }
            // cleanup of cookie
            getResponse().getCookieSettings().remove(DESCRIPTOR_COOKIE);
            CookieSetting disc = new CookieSetting(DESCRIPTOR_COOKIE, "");
            disc.setMaxAge(0);
            getResponse().getCookieSettings().add(disc);
            // TODO save the identifier // send back to OAuth
            return getResponse().getEntity();
        }

        String target = params.getFirstValue("openid_identifier");
        if (target == null || target.length() == 0) {
            // No target - might be Yadis discovery
            String location = setXRDSHeader();
            StringBuilder html = new StringBuilder();
            html.append("<html><head><meta http-equiv=\"X-XRDS-Location\" content=\"");
            html.append(location);
            html.append("\"/></head></html>");
            return new StringRepresentation(html.toString(),
                    MediaType.TEXT_HTML);
        }

        try {
            StringBuilder returnToUrl = new StringBuilder();
            returnToUrl.append(getReference().getBaseRef());
            returnToUrl.append("?return=true");

            // --- Forward proxy setup (only if needed) ---
            // ProxyProperties proxyProps = new ProxyProperties();
            // proxyProps.setProxyName("proxy.example.com");
            // proxyProps.setProxyPort(8080);
            // HttpClientFactory.setProxyProperties(proxyProps);

            // perform discovery on the user-supplied identifier

            List<?> discoveries = null;
            discoveries = discovery.discover(target);
            for (Object o : discoveries) {
                if (o instanceof DiscoveryInformation) {
                    DiscoveryInformation di = (DiscoveryInformation) o;
                    log.info("Found - " + di.getOPEndpoint());
                    target = di.getOPEndpoint().toString();
                }
            }

            ConsumerManager manager = getManager(target);
            // try {
            // discoveries = manager.discover(target);
            // } catch (YadisException e) {
            // log.info("Could not connect in time!!!!!!!!!!!!!!!!!!!!!!");
            // return new
            // StringRepresentation("Could not connect to Identity Server in time.",MediaType.TEXT_HTML);
            // }

            // attempt to associate with the OpenID provider
            // and retrieve one service endpoint for authentication
            DiscoveryInformation discovered = manager.associate(discoveries);

            // store the discovery information in the user's session
            // getContext().getAttributes().put("openid-disc", discovered);
            String sessionId = String.valueOf(System
                    .identityHashCode(discovered));
            session.put(sessionId, discovered);

            getResponse().getCookieSettings().add(
                    new CookieSetting(DESCRIPTOR_COOKIE, sessionId));
            log.info("Setting DESCRIPTOR COOKIE");

            // obtain a AuthRequest message to be sent to the OpenID provider
            AuthRequest authReq = manager.authenticate(discovered,
                    returnToUrl.toString()); // TODO maybe add TIMESTAMP?
            // Domain wide realm add meta to main page
            // http://localhost:8080/oauth/xrds?returnTo=http://localhost:8080/oauth/openid_login\r\n
            // log.info("OpenID - REALM = " +
            // getReference().getHostIdentifier());
            // authReq.setRealm(getReference().getHostIdentifier().toString());
            log.info("OpenID - REALM = " + getReference().getBaseRef());
            authReq.setRealm(getReference().getBaseRef().toString());

            // Attribute Exchange - getting optional and required
            FetchRequest fetch = null;
            String[] optional = params.getValuesArray("ax_optional", true);
            for (String o : optional) {
                if (!ax.containsKey(o)) {
                    log.warning("Not supported AX extension : " + o);
                    continue;
                }
                if (fetch == null)
                    fetch = FetchRequest.createFetchRequest();
                fetch.addAttribute(o, ax.get(o), false);
            }

            String[] required = params.getValuesArray("ax_required", true);
            for (String r : required) {
                if (!ax.containsKey(r)) {
                    log.warning("Not supported AX extension : " + r);
                    continue;
                }
                if (fetch == null)
                    fetch = FetchRequest.createFetchRequest();
                fetch.addAttribute(r, ax.get(r), true);
            }

            if (fetch != null) {
                authReq.addExtension(fetch);
            }

            if (!discovered.isVersion2()) {
                log.info("REDIRECTING TEMPORARY");
                // Option 1: GET HTTP-redirect to the OpenID Provider endpoint
                // The only method supported in OpenID 1.x
                // redirect-URL usually limited ~2048 bytes
                redirectTemporary(authReq.getDestinationUrl(true));
                return null;
            } else {
                // Option 2: HTML FORM Redirection (Allows payloads >2048 bytes)

                Form msg = new Form();
                for (Object key : authReq.getParameterMap().keySet()) {
                    msg.add(key.toString(),
                            authReq.getParameterValue(key.toString()));
                    log.info("Adding to form - key " + key.toString()
                            + " : value"
                            + authReq.getParameterValue(key.toString()));
                }

                // Redirector dispatcher = new Redirector(getContext(),
                // authReq.getOPEndpoint(),
                // Redirector.MODE_SERVER_OUTBOUND);
                // Request req = getRequest();
                // req.setEntity(msg.getWebRepresentation());
                // req.setMethod(Method.POST);
                // dispatcher.handle(getRequest(), getResponse());

                return generateForm(authReq);
            }
        } catch (DiscoveryException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (MessageException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ConsumerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return getResponse().getEntity();
    }

    /**
     * Update the requests headers with OPENID dedicated HTTP headers. Returns
     * the capability document associated with the identity URI.
     *
     * @return The capability document associated with the identity URI.
     */
    private String setXRDSHeader() {
        ConcurrentMap<String, Object> attribs = getContext().getAttributes();
        Reference xrds = new Reference(attribs.get("xrds").toString());
        if ("localhost".equals(xrds.getHostDomain())) {
            // make sure to use the same NIC as original request
            xrds.setHostDomain(getReference().getBaseRef().getHostDomain());
            xrds.setHostPort(getReference().getBaseRef().getHostPort());
        }
        String returnTo = getReference().getBaseRef().toString();
        String location = (returnTo != null) ? xrds.toString() + "?returnTo="
                + returnTo : xrds.toString();
        getLogger().info("XRDS endpoint = " + xrds);
        Form headers = (Form) getResponse().getAttributes().get(
                "org.restlet.http.headers");
        if (headers == null) {
            headers = new Form();
            headers.add("X-XRDS-Location", location);
            getResponse().getAttributes().put("org.restlet.http.headers",
                    headers);
        } else {
            headers.add("X-XRDS-Location", location);
        }
        return location;
    }

    // --- processing the authentication response ---
    @SuppressWarnings("unchecked")
    public Identifier verifyResponse(Map<String, String> axRequired,
            Map<String, String> axOptional) {
        try {
            log.setLevel(Level.FINEST);
            Logger.getLogger("").setLevel(Level.FINEST);
            // extract the parameters from the authentication response
            // (which comes in as a HTTP request from the OpenID provider)
            ParameterList response = new ParameterList(getQuery()
                    .getValuesMap());
            log.info("response = " + response);

            // retrieve the previously stored discovery information
            log.info("GET COOKIES");
            String openidDisc = getCookies().getFirstValue(DESCRIPTOR_COOKIE);
            // String openidDisc =
            // getCookieSettings().getFirstValue(DESCRIPTOR_COOKIE);
            log.info("openIdDiscServer - "
                    + getCookieSettings().getFirstValue("DESCRIPTOR_COOKIE"));
            log.info("openIdDiscServerLength -" + getCookieSettings().size());
            log.info("openIdDiscClient - " + openidDisc);
            log.info("openIdDiscClientLength -" + getCookies().size());

            if (getCookieSettings().size() > 0) {
                for (CookieSetting setting : getCookieSettings()) {
                    log.info("CookieSetting: " + setting.getName()
                            + setting.getFirst());
                }
            }
            if (getCookies().size() > 0) {
                for (Cookie setting : getCookies()) {
                    log.info("Cookie: " + setting.getName()
                            + setting.getFirst());
                }
            }

            DiscoveryInformation discovered = (DiscoveryInformation) session
                    .get(openidDisc); // TODO cleanup

            log.info("discovered = " + discovered);

            // extract the receiving URL from the HTTP request

            log.info("getOriginalRef = " + getOriginalRef());

            // verify the response; ConsumerManager needs to be the same
            // (static) instance used to place the authentication request
            // StringBuilder receivingURL = new StringBuilder();
            // receivingURL.append(getOriginalRef().getScheme(true));
            // receivingURL.append(':');
            // receivingURL.append(getOriginalRef().getSchemeSpecificPart(true));
            // log.info("receivingURL = "+receivingURL);

            log.info("OpenID disc : " + discovered.getOPEndpoint());
            log.info("OpenID orig ref : " + getOriginalRef());
            ConsumerManager manager = getManager(discovered.getOPEndpoint()
                    .toString());

            VerificationResult verification = manager.verify(getOriginalRef()
                    .toString(), response, discovered);
            log.info("verification = " + verification);

            // examine the verification result and extract the verified
            // identifier
            Identifier verified = verification.getVerifiedId();
            log.info("verified = " + verified);
            if (verified != null) {
                AuthSuccess authSuccess = (AuthSuccess) verification
                        .getAuthResponse();

                if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
                    FetchRequest fetchResp = (FetchRequest) authSuccess
                            .getExtension(AxMessage.OPENID_NS_AX);

                    MessageExtension ext = authSuccess
                            .getExtension(AxMessage.OPENID_NS_AX);
                    if (ext instanceof FetchRequest) {
                        // FetchRequest fetchReq = (FetchRequest) ext;
                        Map<String, String> required = fetchResp
                                .getAttributes(true);
                        axRequired.putAll(required);
                        Map<String, String> optional = fetchResp
                                .getAttributes(false);
                        axOptional.putAll(optional);
                    }
                }

                return verified; // success
            }
        } catch (OpenIDException e) {
            log.log(Level.INFO, "", e);
        }
        log.setLevel(Level.INFO);
        return null;
    }

}
TOP

Related Classes of org.restlet.ext.openid.internal.OpenIdConsumer

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.