Package com.cosmo.security.auth.impl

Source Code of com.cosmo.security.auth.impl.CasAuthenticationImpl

package com.cosmo.security.auth.impl;

import java.io.IOException;
import java.io.StringReader;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.cosmo.Workspace;
import com.cosmo.net.HttpRequestUtils;
import com.cosmo.net.URL;
import com.cosmo.security.User;
import com.cosmo.security.UserNotFoundException;
import com.cosmo.security.annotations.LoginGatewayAgent;
import com.cosmo.security.auth.Authentication;
import com.cosmo.security.auth.AuthenticationException;
import com.cosmo.util.PluginProperties;
import com.cosmo.util.StringUtils;

/**
* Implementaci�n del agente de autenticaci�n para CAS 2.0.
*
* @version 1.0.0
* @author Gerard Llort
*/
@LoginGatewayAgent
public class CasAuthenticationImpl implements Authentication
{
   // Par�metros URL
   private static String URL_PARAM_TICKET = "ticket";
   private static String URL_PARAM_SERVICE = "service";
  
   // Llamadas URL
   private static final String SERVICE_VALIDATE_URL_PART = "serviceValidate";
   private static final String LOGIN_URL_PART = "login";
  
   // Tags XML para el parseo de las respuestas de CAS
   private static String TAG_CAS_USER = "user";
   private static String TAG_CAS_PROPERTY = "attribute";
   private static String TAG_CAS_ATTRIBNAME = "name";
   private static String TAG_CAS_ATTRIBVALUE = "value";
  
   // Constantes para obtener las propiedades de configuraci�n del agente
   private static String AGENT_PARAM_CASSERVICE = "cas-service";
   private static String AGENT_PARAM_SERVICEURL = "service-url";
   private static String CAS_ATTRIB_MAIL = "cas-attrib-mail";
   private static String CAS_ATTRIB_COMPLETNAME = "cas-attrib-cname";
   private static String CAS_ATTRIB_NAME = "cas-attrib-name";
   private static String CAS_ATTRIB_SURNAME = "cas-attrib-surname";
  
   private Workspace workspace;
   private PluginProperties agent;
   private String serviceTicket;
   private HttpClient httpClient;
  
   //==============================================
   // Constructors
   //==============================================
  
   /**
    * Constructor de la clase.
    *
    * @param workspace Una instancia de {@link Workspace} que representa el workspace al que est� conectado actualmente.
    */
   public CasAuthenticationImpl(Workspace workspace)
   {
      this.serviceTicket = "";
      this.httpClient = new HttpClient();
      this.workspace = workspace;
      this.agent = this.workspace.getProperties().getSecurityProperties().getAuthenticationAgent();
   }
  
  
   //==============================================
   // Properties
   //==============================================
  
   /**
    * Devuelve el Ticket Granting Ticket de CAS.
    *
    * @return Una cadena que contiene el Ticket Granting Ticket de CAS.
    */
   public String getGrantingTicket()
   {
      return this.serviceTicket;
   }
  
   /**
    * Devuelve un {@code hash} que contiene los par�metros de configuraci�n del agente de seguridad.
    */
   public HashMap<String, String> getParameters()
   {
      return agent.getParams();
   }
  
  
   //==============================================
   // Methods
   //==============================================
  
   /**
    * Verifica las credenciales de un usuario.
    *
    * @param login Login del usuario.
    * @param password Contrase�a (sin encriptar) del usuario.
    * @return Una instancia de {@link User} que representa el usuario al que corresponden las credenciales proporcionadas.
    *
    * @throws UserNotFoundException
    * @throws AuthenticationException
    */
   @Override
   public User login(String login, String password) throws UserNotFoundException, AuthenticationException
   {
      // Este agente usa Login Gateway por lo que este m�todo no se invocar� nunca.
      return null;
   }
  
   /**
    * Elimina la informaci�n de autenticaci�n actual.
    */
   @Override
   public void logout()
   {
      return;
   }
  
   /**
    * Revalida la sesi�n de usuario.
    */
   @Override
   public void validate()
   {
      return;  
   };
  
   /**
    * Indica si una respuesta corresponde al retorno de la acci�n de login.
    *
    * @param request Una instancia de {@link HttpServletRequest} que cotniene el contexto de la llamada.
    *
    * @return {@code true} si la petici�n corresponde al retorno de la pantalla de login o {@code false} en cualquier otro caso.
    */
   public boolean isLoginGatewayResponse(HttpServletRequest request)
   {
      String st = HttpRequestUtils.getValue(request, URL_PARAM_TICKET);
      return (st != null && !st.isEmpty());
   }
  
   /**
    * Devuelve la URL usada para la autenticaci�n de usuarios.
    */
   public String getLoginGatewayUrl()
   {
      URL url = new URL(agent.getParamString(AGENT_PARAM_CASSERVICE).trim());
      url.addFolderOrFile(LOGIN_URL_PART);
      url.addParameter(URL_PARAM_SERVICE, agent.getParamString(AGENT_PARAM_SERVICEURL));
     
      return url.toString();
   }
  
   /**
    * Detecta si una autenticaci�n delegada (Login Gateway) ha sido exitosa.<br />
    * Las clases que extiendan a {@link Authentication} ser�n responsables de obtener los datos del usuario
    * autenticado en el sistema externo, ya sea mediante servicios REST u otros mecanismos.
    *
    * @param request Una instancia de {@link HttpServletRequest} que cotniene el contexto de la llamada.
    *
    * @return Una instancia de {@link User} que contiene las propiedades del usuario autenticado o {@code null} en cualquier otro caso.
    */
   @Override
   public User getLoginGatewayUser(HttpServletRequest request)
   {
      try
      {
         // Obtiene el ServiceTicket
         serviceTicket = HttpRequestUtils.getValue(request, URL_PARAM_TICKET);
  
         if (!StringUtils.isNullOrEmpty(serviceTicket))
         {
            // Valida el ticket y obtiene una instancia con las propiedades del usuario
            return validate(agent.getParamString(AGENT_PARAM_SERVICEURL), serviceTicket);
         }
         else
         {
            return null;
         }
      }
      catch (AuthenticationException ex)
      {
         return null;
      }
   }
  
  
   //==============================================
   // Private members
   //==============================================
  
   /**
    * Valida el ticket obtenido del servidor CAS para la URL del servicio (aplicaci�n).
    *
    * @param serviceUrl Una cadena que representa la URL del servicio (aplicaci�n).
    * @param serviceTicket Una cadena que contiene el Service Ticket obtenido en el retorno de la pantalla de Login.
    *
    * @return Una instancia de {@link User} si la validaci�n es correcta o {@code null} en cualquier otro caso.
    *
    * @throws AuthenticationException
    */
   private User validate(String serviceUrl, String serviceTicket) throws AuthenticationException
   {
      User user = null;
     
      URL url = new URL(agent.getParamString(AGENT_PARAM_CASSERVICE));
      url.addFolderOrFile(SERVICE_VALIDATE_URL_PART);
     
      String toUrl = url.toString();
     
      PostMethod method = new PostMethod(toUrl);
      method.setParameter(URL_PARAM_SERVICE, serviceUrl);
      method.setParameter(URL_PARAM_TICKET, serviceTicket);
     
      try
      {
         int statusCode = httpClient.executeMethod(method);
        
         if (statusCode != HttpStatus.SC_OK)
         {
            method.releaseConnection();
            throw new AuthenticationException("El servidor de CAS no ha respondido correctamente a la llamada de validaci�n de la autenticaci�n (CAS ticket=" + serviceTicket + ").");
         }
         else
        
            String resp = new String(method.getResponseBody());           
            user = getUserDataFromValidation(resp);

            // result = extractUser(new String(method.getResponseBody()));
         }
      }
      catch (IOException ex)
      {
         throw new AuthenticationException(ex.getMessage(), ex);
      }
      catch (AuthenticationException ex)
      {
         throw ex;
      }
      finally
      {
         method.releaseConnection();
      }
     
      return user;
   }
  
   /**
    * Parsea la respuesta de la validaci�n de ticket de CAS y extrae la informaci�n del usuario.
    *
    * @param responseData Una cadena que contiene la respuesta del servidor CAS (en formato XML).
    *
    * @return Una instancia de {@link User} que contiene los datos del usuario.
    *
    * @throws AuthenticationException
    */
   public User getUserDataFromValidation(String responseData) throws AuthenticationException
   {
      Node nNode;
      NodeList nList;
      SimpleEntry<String, String> attrib = null;
      User user = null;
     
      try
      {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setNamespaceAware(true);

         DocumentBuilder builder = factory.newDocumentBuilder();
         Document doc = builder.parse(new InputSource(new StringReader(responseData)));
         doc.getDocumentElement().normalize();
        
         // Obtiene el LOGIN del usuario
         nList = doc.getElementsByTagNameNS("*", TAG_CAS_USER);
         for (int temp = 0; temp < nList.getLength(); temp++)
         {
            nNode = nList.item(0);
            if (nNode.getNodeType() == Node.ELEMENT_NODE)
            {
               user = new User();
               user.setLogin(nNode.getFirstChild().getNodeValue());
               break;
            }
         }
        
         // Si no se ha podido extraer el usuario, se devuelve null
         if (user == null)
         {
            return user;
         }
        
         // Obtiene las PROPIEDADES del usuario
         nList = doc.getElementsByTagNameNS("*", TAG_CAS_PROPERTY);
         for (int temp = 0; temp < nList.getLength(); temp++)
         {
            nNode = nList.item(temp);
            if (nNode.getNodeType() == Node.ELEMENT_NODE)
            {
               attrib = getResponseAttribute((Element) nNode);
               setUserAttribute(user, attrib.getKey(), attrib.getValue());
            }
         }
        
         return user;
      }
      catch (ParserConfigurationException ex)
      {
         throw new AuthenticationException(ex.getMessage(), ex);
      }
      catch (SAXException ex)
      {
         throw new AuthenticationException(ex.getMessage(), ex);
      }
      catch (IOException ex)
      {
         throw new AuthenticationException(ex.getMessage(), ex);
      }
   }
  
   /**
    * Obtiene los valores (nombre y valor) de un atributo de usuario en la respuesta del servidor CAS.
    *
    * @param attribNode Una instancia de {@link Element} que representa el nodo ra�z del atributo a leer.
    * @param name La cadena que se actualizar� con el nombre del atributo.
    * @param value La cadena que se actualizar� con el valor del atributo.
    */
   private SimpleEntry<String, String> getResponseAttribute(Element attribNode)
   {
      String name = "";
      String value = "";
      Node node;
      NodeList nList;
     
      nList = attribNode.getElementsByTagNameNS("*", TAG_CAS_ATTRIBNAME);
      if (nList.getLength() > 0)
      {
         node = nList.item(0);
         name = node.getFirstChild().getNodeValue();
      }
     
      nList = attribNode.getElementsByTagNameNS("*", TAG_CAS_ATTRIBVALUE);
      if (nList.getLength() > 0)
      {
         node = nList.item(0);
         value = node.getFirstChild().getNodeValue();
      }

      if (!name.isEmpty())
      {
         return new SimpleEntry<String, String>(name, value);
      }
      else
      {
         return null;
      }
   }
  
   /**
    * Establece un atributo del usuario.<br />
    * Si el nombre de la propiedad es desconocida, se omite cualquier acci�n.
    *
    * @param user La instancia de {@link User} que va a ser actualizada.
    * @param name Nombre del atributo a actualizar (constantes {@code CAS_ATTRIB_XXXX}).
    * @param value Valor que va a tomar el atributo.
    */
   private void setUserAttribute(User user, String name, String value)
   {
      if (agent.getParamString(CAS_ATTRIB_MAIL) != null &&
          agent.getParamString(CAS_ATTRIB_MAIL).equalsIgnoreCase(name))
      {
         user.setMail(value);
         return;
      }

      if (agent.getParamString(CAS_ATTRIB_NAME) != null &&
          agent.getParamString(CAS_ATTRIB_NAME).equalsIgnoreCase(name))
      {
         user.setName(value);
         return;
      }
     
      if (agent.getParamString(CAS_ATTRIB_SURNAME) != null &&
          agent.getParamString(CAS_ATTRIB_SURNAME).equalsIgnoreCase(name))
      {
         user.setName(user.getName() + " " + value);
         return;
      }
     
      if (agent.getParamString(CAS_ATTRIB_COMPLETNAME) != null &&
          agent.getParamString(CAS_ATTRIB_COMPLETNAME).equalsIgnoreCase(name))
      {
         user.setName(value);
         return;
      }
   }
  
/*  
  
   // public static Logger LOG = Logger.getLogger( CasClient.class  );
  
   public static final String TICKET_BEGIN = "ticket=";
   private static final String LT_BEGIN = "name=\"lt\" value=\"";
   public static final String CAS_USER_BEGIN = "<cas:user>";
   public static final String CAS_USER_END = "</cas:user>";
 
   private HttpClient fClient;
   private String fCasUrl;
 
   // public String
 
   / **
    * Authenticate the specified username with the specified password.
    * This will not yield any ticket, as no service is authenticated
    * against. This wil just set the CAS cookie in this client upon
    * successful authentication.
    *
    * @param username
    * @param password
    * /
   public void authenticate(String username, String password)
   {
      authenticate(null, username, password);
   }
 
   / **
    * Authenticate the specified user with the specified password against the specified service.
    *
    * @param serviceUrl May be null. If a url is specified, the authentication will happen against this service, yielding a service ticket which can be validated.
    * @param username
    * @param password
    * @return A valid service ticket, if and only if the specified service URL is not null.
    * /
   public String authenticate(String serviceUrl, String username, String password)
   {
      String lt = getLt(serviceUrl);
      String result = null;
      PostMethod method = null;
      
      if (lt == null)
      {
         // LOG.error( "Cannot retrieve LT from CAS. Aborting authentication for '" + username + "'" );
         return null;
      }
      
      method = new PostMethod(fCasUrl + LOGIN_URL_PART);

      / *if (serviceUrl != null) // optional
      {
         method.setParameter("service", serviceUrl);
      }
      method.setParameter("_eventId", "submit");
      method.setParameter("username", username);
      method.setParameter("password", password);
      method.setParameter("lt", lt);
      method.setParameter("gateway", "true");* /
     
      method.setRequestBody(new NameValuePair[]
      {
         new NameValuePair("service", serviceUrl),
         new NameValuePair("_eventId", "submit"),
         new NameValuePair("username", username),
         new NameValuePair("password", password),
         new NameValuePair("lt", lt),
         new NameValuePair("gateway", "true")
      });
     
      try
      {
         fClient.executeMethod(method);
          
         if (serviceUrl == null)
         {
            // if CAS does not return a login page with an LT authentication was successful
            if (extractLt(new String(method.getResponseBody())) != null)
            {
               // LOG.error("Authentication for '" +  username + "' unsuccessful");
               // if (LOG.isDebugEnabled())
               // {
                  // LOG.debug( "Authentication for '" + username + "' unsuccessful." );
               // }
            }
            else
            {
               // if (LOG.isDebugEnabled())
               // {
               //    LOG.debug( "Authentication for '" + username + "' unsuccessful." );
               // }
            }
         }
         else
         {
            Header h = method.getResponseHeader("Location");
              
            if (h != null)
            {
               result = extractServiceTicket(h.getValue());
            }
              
            if (result == null)
            {
               // LOG.error( "Authentication for '" + username + "' unsuccessful." );
            }
         }
      }
      catch (Exception x)
      {
         // LOG.error( "Could not authenticate'" + username + "':" + x.toString () );
      }
      finally
      {
         method.releaseConnection();
      }
      
      return result;
   }
  
  
 
   / **
    * Helper method to extract the user name from a "service validate" call to CAS.
    *
    * @param data Response data.
    * @return The clear text username, if it could be extracted, null otherwise.
    * /
   protected String extractUser(String data)
   {
      int start;
      int end;
      String user = null;
     
      start = data.indexOf(CAS_USER_BEGIN);
      
      if (start >= 0)
      {
         start += CAS_USER_BEGIN.length();
         end = data.indexOf(CAS_USER_END);
          
         if (end > start)
         {
            user = data.substring(start, end);
         }
         else
         {
            // LOG.warn("Could not extract username from CAS validation response. Raw data is: '" + data + "'" );
         }
      }
      else
      {
         // LOG.warn("Could not extract username from CAS validation response. Raw data is: '" + data + "'" );
      }

      return user;
   }
 
   / **
    * Helper method to extract the service ticket from a login call to CAS.
    *
    * @param data Response data.
    * @return The service ticket, if it could be extracted, null otherwise.
    * /
   protected String extractServiceTicket(String data)
   {
      int start;
      String serviceTicket = null;
     
      start = data.indexOf(TICKET_BEGIN);

      if (start > 0)
      {
         start += TICKET_BEGIN.length();
         serviceTicket = data.substring(start);
      }

      return serviceTicket;
   }
 
   / **
    * Helper method to extract the LT from a login form from CAS.
    *
    * @param data Response data.
    * @return The LT, if it could be extracted, null otherwise.
    * /
   protected String extractLt(String data)
   {
      int start;
      int end;
      String token = null;
     
      start = data.indexOf(LT_BEGIN);
      
      if ( start < 0 )
      {
         // LOG.error( "Could not obtain LT token from CAS: LT Token not found in response." );
      }
      else
      {
         start += LT_BEGIN.length();
         end = data.indexOf("\"", start);
         token = data.substring(start, end);
      }

      return token;
   }
 
   / **
    * This method requests the original login form from CAS.
    * This form contains an LT, an initial token that must be
    * presented to CAS upon sending it an authentication request
    * with credentials.<br>
    * If a service URL is provided (which is optional), this method
    * will post the URL such that CAS authenticates against the
    * specified service when a subsequent authentication request is
    * sent.
    *
    * @param serviceUrl
    * @return The LT token if it could be extracted from the CAS response.
    * /
   protected String getLt(String serviceUrl)
   {
       String lt = null;
       HttpMethod method = null;
      
       if (serviceUrl == null)
       {
           method = new GetMethod(fCasUrl + LOGIN_URL_PART);
       }
       else
       {
           method = new PostMethod(fCasUrl + LOGIN_URL_PART);
           ((PostMethod) method).setParameter("service", serviceUrl);
       }

       try
       {
           int statusCode = fClient.executeMethod(method);
          
           if (statusCode != HttpStatus.SC_OK)
           {
               // LOG.error( "Could not obtain LT token from CAS: " + method.getStatusLine() );
               method.releaseConnection();
           }
           else
           {
               // Object o = method.getResponseHeaders();
               method.getResponseHeaders();
               return extractLt(new String(method.getResponseBody()));
           }
       }
       catch (Exception x)
       {
           // LOG.error( "Could not obtain LT token from CAS: " + x.toString ());
       }
       finally
       {
          method.releaseConnection();
       }
      
       return lt;
   }
  
  
  
  
  
   public static void main(String[] args)
   {
     
     
      String str = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" +
                   "<cas:authenticationSuccess>\n" +
                   "  <cas:user>gllort</cas:user>\n" +
                   "  <!-- Begin Ldap Attributes -->\n" +
                   "    <cas:attributes>\n" +
                   "      <cas:attribute>\n" +
                   "        <cas:name>mail</cas:name>\n" +
                   "        <cas:value>gllort@altanet.org</cas:value>\n" +
                   "      </cas:attribute>\n" +
                   "      <cas:attribute>\n" +
                   "        <cas:name>nif</cas:name>\n" +
                   "        <cas:value>46725607A</cas:value>\n" +
                   "      </cas:attribute>\n" +
                   "      <cas:attribute>\n" +
                   "        <cas:name>nomComplet</cas:name>\n" +
                   "        <cas:value>Gerard Llort Casanova</cas:value>\n" +
                   "      </cas:attribute>\n" +
                   "    </cas:attributes>\n" +
                   "  </cas:authenticationSuccess>\n" +
                   "</cas:serviceResponse>";
     
      try
      {
         System.out.print(getUserDataFromValidation(str));
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }
  
   */
}
 
TOP

Related Classes of com.cosmo.security.auth.impl.CasAuthenticationImpl

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.