Package org.exist.security.realm.openid

Source Code of org.exist.security.realm.openid.AuthenticatorOpenIdServlet

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2009-2011 The eXist Project
*  http://exist-db.org
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*  This program 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 Lesser General Public License for more details.
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*  $Id$
*/
package org.exist.security.realm.openid;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.security.auth.Subject;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.exist.Database;
import org.exist.EXistException;
import org.exist.config.ConfigurationException;
import org.exist.security.AXSchemaType;
import org.exist.security.AbstractAccount;
import org.exist.security.Account;
import org.exist.security.AbstractRealm;
import org.exist.security.PermissionDeniedException;
import org.exist.security.internal.HttpSessionAuthentication;
import org.exist.security.internal.SubjectAccreditedImpl;
import org.exist.security.internal.aider.UserAider;
import org.exist.xquery.util.HTTPUtils;
import org.openid4java.OpenIDException;
import org.openid4java.association.AssociationSessionType;
import org.openid4java.consumer.*;
import org.openid4java.discovery.*;
import org.openid4java.message.*;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.openid4java.message.sreg.SRegMessage;
import org.openid4java.message.sreg.SRegRequest;
import org.openid4java.message.sreg.SRegResponse;
import org.openid4java.util.*;

/**
* OpenId authenticator servlet.
*
* @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
*
*/
public class AuthenticatorOpenIdServlet extends HttpServlet {

  private static final long serialVersionUID = -558037449837549034L;

  private static final Log LOG = LogFactory.getLog(AuthenticatorOpenIdServlet.class);

    public ConsumerManager manager;
   
    public static AbstractRealm realm = null;

  public AuthenticatorOpenIdServlet() throws ConsumerException {
  }

    @Override
  public void init(ServletConfig config) throws ServletException {
    super.init(config);

    // --- Forward proxy setup (only if needed) ---
    ProxyProperties proxyProps = getProxyProperties(config);
    if (proxyProps != null) {
      LOG.debug("ProxyProperties: " + proxyProps);
      HttpClientFactory.setProxyProperties(proxyProps);
    }

    manager = new ConsumerManager();
    manager.setAssociations(new InMemoryConsumerAssociationStore());
    manager.setNonceVerifier(new InMemoryNonceVerifier(5000));
    manager.setMinAssocSessEnc(AssociationSessionType.DH_SHA256);
  }

    @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    doPost(req, resp);
  }

    @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    if ("true".equals(req.getParameter("is_return"))) {
      processReturn(req, resp);
    } else {
      String identifier = req.getParameter("openid_identifier");
      if (identifier != null) {
        this.authRequest(identifier, req, resp);
      } else {
        //this.getServletContext().getRequestDispatcher("/openid/login.xql").forward(req, resp);
        resp.sendRedirect(
          OpenIDRealm.instance.getSecurityManager().getAuthenticationEntryPoint()
        );
      }
    }
  }

  private void processReturn(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    Account principal = this.verifyResponse(req);
   
    //System.out.println(principal);
       
    String returnURL = req.getParameter("exist_return");

        if (principal == null) {
      //this.getServletContext().getRequestDispatcher("/openid/login.xql").forward(req, resp);
      resp.sendRedirect(returnURL);
    } else {
          HttpSession session = req.getSession(true);

      //((XQueryURLRewrite.RequestWrapper)req).setUserPrincipal(principal);

      Subject subject = new Subject();
     
      //TODO: hardcoded to jetty - rewrite
      //*******************************************************
      DefaultIdentityService _identityService = new DefaultIdentityService();
      UserIdentity user = _identityService.newUserIdentity(subject, principal, new String[0]);
           
      Authentication cached=new HttpSessionAuthentication(session, user);
            session.setAttribute(HttpSessionAuthentication.__J_AUTHENTICATED, cached);
      //*******************************************************
           
      resp.sendRedirect(returnURL);
    }
  }

  // authentication request
  public String authRequest(String userSuppliedString,
      HttpServletRequest httpReq, HttpServletResponse httpResp)
      throws IOException, ServletException {

    if (OpenIDRealm.instance == null) {
      ServletOutputStream out = httpResp.getOutputStream();
          httpResp.setContentType("text/html; charset=\"UTF-8\"");
          httpResp.addHeader( "pragma", "no-cache" );
          httpResp.addHeader( "Cache-Control", "no-cache" );

          httpResp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

          out.print("<html><head>");
          out.print("<title>OpenIDServlet Error</title>");
          out.print("<link rel=\"stylesheet\" type=\"text/css\" href=\"error.css\"></link></head>");
          out.print("<body><div id=\"container\"><h1>Error found</h1>");
           
          out.print("<h2>Message:");
            out.print("OpenID realm wasn't initialized.");
            out.print("</h2>");
         
            //out.print(HTTPUtils.printStackTraceHTML(t));
         
          out.print("</div></body></html>");
          return null;
    }
    try {
      String returnAfterAuthentication = httpReq.getParameter("return_to");

      // configure the return_to URL where your application will receive
      // the authentication responses from the OpenID provider
      String returnToUrl = httpReq.getRequestURL().toString() + "?is_return=true&exist_return="+returnAfterAuthentication;

      // perform discovery on the user-supplied identifier
      List<?> discoveries = manager.discover(userSuppliedString);

      // 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
      httpReq.getSession().setAttribute("openid-disc", discovered);

      // obtain a AuthRequest message to be sent to the OpenID provider
      AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
     
      if (authReq.getOPEndpoint().indexOf("myopenid.com")>0) {
        SRegRequest sregReq = SRegRequest.createFetchRequest();

        sregReq.addAttribute(AXSchemaType.FULLNAME.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.EMAIL.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.COUNTRY.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.LANGUAGE.name().toLowerCase(), true);

        authReq.addExtension(sregReq);
      } else {

        FetchRequest fetch = FetchRequest.createFetchRequest();

        fetch.addAttribute(AXSchemaType.FIRSTNAME.getAlias(), AXSchemaType.FIRSTNAME.getNamespace(), true);
        fetch.addAttribute(AXSchemaType.LASTNAME.getAlias(), AXSchemaType.LASTNAME.getNamespace(), true);
        fetch.addAttribute(AXSchemaType.EMAIL.getAlias(), AXSchemaType.EMAIL.getNamespace(), true);
        fetch.addAttribute(AXSchemaType.COUNTRY.getAlias(), AXSchemaType.COUNTRY.getNamespace(), true);
        fetch.addAttribute(AXSchemaType.LANGUAGE.getAlias(), AXSchemaType.LANGUAGE.getNamespace(), true);

        // wants up to three email addresses
        fetch.setCount(AXSchemaType.EMAIL.getAlias(), 3);

        authReq.addExtension(fetch);
      }
     
      if (!discovered.isVersion2()) {
        // Option 1: GET HTTP-redirect to the OpenID Provider endpoint
        // The only method supported in OpenID 1.x
        // redirect-URL usually limited ~2048 bytes
        httpResp.sendRedirect(authReq.getDestinationUrl(true));
        return null;

      } else {
        // Option 2: HTML FORM Redirection (Allows payloads >2048 bytes)

        Object OPEndpoint = authReq.getDestinationUrl(false);
       
        ServletOutputStream out = httpResp.getOutputStream();
           
        httpResp.setContentType("text/html; charset=UTF-8");
        httpResp.addHeader( "pragma", "no-cache" );
        httpResp.addHeader( "Cache-Control", "no-cache" );

            out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
        out.println("<head>");
        out.println("    <title>OpenID HTML FORM Redirection</title>");
        out.println("</head>");
        out.println("<body onload=\"document.forms['openid-form-redirection'].submit();\">");
        out.println("    <form name=\"openid-form-redirection\" action=\""+OPEndpoint+"\" method=\"post\" accept-charset=\"utf-8\">");

        Map<String, String> parameterMap = authReq.getParameterMap();
        for (Entry<String, String> entry : parameterMap.entrySet()) {
          out.println("  <input type=\"hidden\" name=\""+entry.getKey()+"\" value=\""+entry.getValue()+"\"/>");
        }
       
        out.println("        <button type=\"submit\">Continue...</button>");
        out.println("    </form>");
        out.println("</body>");
        out.println("</html>");
       
        out.flush();
      }
    } catch (OpenIDException e) {
      // present error to the user
      LOG.debug("OpenIDException",e);

      ServletOutputStream out = httpResp.getOutputStream();
          httpResp.setContentType("text/html; charset=\"UTF-8\"");
          httpResp.addHeader( "pragma", "no-cache" );
          httpResp.addHeader( "Cache-Control", "no-cache" );

          httpResp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

          out.print("<html><head>");
          out.print("<title>OpenIDServlet Error</title>");
          out.print("<link rel=\"stylesheet\" type=\"text/css\" href=\"error.css\"></link></head>");
          out.print("<body><div id=\"container\"><h1>Error found</h1>");
           
          out.print("<h2>Message:");
            out.print(e.getMessage());
            out.print("</h2>");
         
          Throwable t = e.getCause();
          if(t!=null){
              // t can be null
              out.print(HTTPUtils.printStackTraceHTML(t));
          }
         
          out.print("</div></body></html>");
    }

    return null;
  }

  // authentication response
  public Account verifyResponse(HttpServletRequest httpReq)
      throws ServletException {

    try {
      // extract the parameters from the authentication response
      // (which comes in as a HTTP request from the OpenID provider)
      ParameterList response = new ParameterList(httpReq
          .getParameterMap());

      // retrieve the previously stored discovery information
      DiscoveryInformation discovered = (DiscoveryInformation) httpReq
          .getSession().getAttribute("openid-disc");

      // extract the receiving URL from the HTTP request
      StringBuffer receivingURL = httpReq.getRequestURL();
      String queryString = httpReq.getQueryString();
      if (queryString != null && queryString.length() > 0)
        receivingURL.append("?").append(httpReq.getQueryString());

      // verify the response; ConsumerManager needs to be the same
      // (static) instance used to place the authentication request
      VerificationResult verification = manager.verify(receivingURL.toString(), response, discovered);

      // examine the verification result and extract the verified
      // identifier
      Identifier verified = verification.getVerifiedId();
      if (verified != null) {
        // success
       
        String accountName = AccountImpl.escape(verified.getIdentifier());
        AbstractAccount account = (AbstractAccount) OpenIDRealm.instance.getAccount(accountName);
        if (account == null) {
          Database db = OpenIDRealm.instance.getDatabase();
          org.exist.security.Subject currentSubject = db.getSubject();
          try {
            db.setSubject(db.getSecurityManager().getSystemSubject());
         
            //XXX: set OpenID group by default
            account = (AbstractAccount) OpenIDRealm.instance.addAccount(
                new UserAider(OpenIDRealm.instance.getId(), accountName)
              );
          } finally {
            db.setSubject(currentSubject);
          }
        }
       
        org.exist.security.Subject principal =
          new SubjectAccreditedImpl( account, verified );
       
        AuthSuccess authSuccess = (AuthSuccess) verification.getAuthResponse();
        authSuccess.getExtensions();

        if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) {
          MessageExtension ext = authSuccess.getExtension(SRegMessage.OPENID_NS_SREG);
          if (ext instanceof SRegResponse) {
            SRegResponse sregResp = (SRegResponse) ext;
            for (Iterator iter = sregResp.getAttributeNames().iterator(); iter.hasNext();) {
              String name = (String) iter.next();
              if (LOG.isDebugEnabled())
                LOG.debug(name + " : " + sregResp.getParameterValue(name));
              principal.setMetadataValue(AXSchemaType.valueOfNamespace(name), sregResp.getParameterValue(name));
            }
          }
        }
        if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
          FetchResponse fetchResp = (FetchResponse) authSuccess.getExtension(AxMessage.OPENID_NS_AX);

          List aliases = fetchResp.getAttributeAliases();
          for (Iterator iter = aliases.iterator(); iter.hasNext();) {
            String alias = (String) iter.next();
            List values = fetchResp.getAttributeValues(alias);
            if (values.size() > 0) {
              if (LOG.isDebugEnabled())
                LOG.debug(alias + " : " + values.get(0));
              principal.setMetadataValue(AXSchemaType.valueOfAlias(alias), (String)values.get(0));
            }
          }
        }
        //update metadata
        Database db = OpenIDRealm.instance.getDatabase();
        org.exist.security.Subject currentSubject = db.getSubject();
        try {
          db.setSubject(db.getSecurityManager().getSystemSubject());
       
          OpenIDRealm.instance.updateAccount(principal);
        } finally {
          db.setSubject(currentSubject);
        }
       
                OpenIDUtility.registerUser(principal);
        return principal;
      }
    } catch (OpenIDException e) {
      LOG.error(e);
    } catch (ConfigurationException e) {
      LOG.error(e);
    } catch (PermissionDeniedException e) {
      LOG.error(e);
    } catch (EXistException e) {
      LOG.error(e);
    }

    return null;
  }

  private static ProxyProperties getProxyProperties(ServletConfig config) {
    ProxyProperties proxyProps;
    String host = config.getInitParameter("proxy.host");
    LOG.debug("proxy.host: " + host);
    if (host == null) {
      proxyProps = null;
    } else {
      proxyProps = new ProxyProperties();
      String port = config.getInitParameter("proxy.port");
      String username = config.getInitParameter("proxy.username");
      String password = config.getInitParameter("proxy.password");
      String domain = config.getInitParameter("proxy.domain");
      proxyProps.setProxyHostName(host);
      proxyProps.setProxyPort(Integer.parseInt(port));
      proxyProps.setUserName(username);
      proxyProps.setPassword(password);
      proxyProps.setDomain(domain);
    }
    return proxyProps;
  }

}
TOP

Related Classes of org.exist.security.realm.openid.AuthenticatorOpenIdServlet

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.