Package org.apache.jetspeed.sso.impl

Source Code of org.apache.jetspeed.sso.impl.PersistenceBrokerSSOProvider

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jetspeed.sso.impl;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.security.auth.Subject;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.components.dao.InitablePersistenceBrokerDaoSupport;
import org.apache.jetspeed.security.BasePrincipal;
import org.apache.jetspeed.security.SecurityHelper;
import org.apache.jetspeed.security.UserPrincipal;
import org.apache.jetspeed.security.impl.GroupPrincipalImpl;
import org.apache.jetspeed.security.impl.UserPrincipalImpl;
import org.apache.jetspeed.security.om.InternalCredential;
import org.apache.jetspeed.security.om.InternalGroupPrincipal;
import org.apache.jetspeed.security.om.InternalUserPrincipal;
import org.apache.jetspeed.security.om.impl.InternalCredentialImpl;
import org.apache.jetspeed.security.om.impl.InternalGroupPrincipalImpl;
import org.apache.jetspeed.security.om.impl.InternalUserPrincipalImpl;
import org.apache.jetspeed.security.spi.impl.DefaultPasswordCredentialImpl;
import org.apache.jetspeed.sso.SSOContext;
import org.apache.jetspeed.sso.SSOException;
import org.apache.jetspeed.sso.SSOPrincipal;
import org.apache.jetspeed.sso.SSOProvider;
import org.apache.jetspeed.sso.SSOSite;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.QueryByCriteria;
import org.apache.ojb.broker.query.QueryFactory;


/**
* <p>Utility component to handle SSO requests</p>
*
* @author <a href="mailto:rogerrut@apache.org">Roger Ruttimann</a>
*/
public class PersistenceBrokerSSOProvider extends
    InitablePersistenceBrokerDaoSupport implements SSOProvider
  /* Logging */
  private static final Log log = LogFactory.getLog(PersistenceBrokerSSOProvider.class);
 
  /*
   * Cache for sites and Proxy sites
   */
  private Hashtable mapSite = new Hashtable();
  private Hashtable clientProxy = new Hashtable();
 
    private String USER_PATH = "/user/";
    private String GROUP_PATH = "/group/";

    /**
     * PersitenceBrokerSSOProvider()
     * @param repository Location of repository mapping file.  Must be available within the classpath.
     * @param prefsFactoryImpl <code>java.util.prefs.PreferencesFactory</code> implementation to use.
     * @param enablePropertyManager  Whether or not we chould be suing the property manager.
     * @throws ClassNotFoundException if the <code>prefsFactoryImpl</code> argument does not reperesent
     * a Class that exists in the current classPath.
     */
    public PersistenceBrokerSSOProvider(String repositoryPath) throws ClassNotFoundException
    {
       super(repositoryPath);
    }
   
   
    /*
     *  (non-Javadoc)
     * @see org.apache.jetspeed.sso.SSOProvider#useSSO(java.lang.String, java.lang.String, java.lang.String)
     */
    public String useSSO(Subject subject, String url, String SSOSite, boolean bRefresh) throws SSOException
    {
      // Get the principal from the subject
    BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
    String fullPath = principal.getFullPath();
   
      /* ProxyID is used for the cache. The http client object will be cached for a
       * given user site url combination
       */
      String proxyID = fullPath + "_" + SSOSite;
     
      // Get the site
      SSOSite ssoSite = getSSOSiteObject(SSOSite);
   
    if ( ssoSite != null)
    {
      SSOSite[] sites = new SSOSite[1];
      sites[0] = ssoSite;
     
      return this.getContentFromURL(proxyID, url, sites, bRefresh);
    }
    else
    {
      // Site doesn't exist -- log an error but continue
      String msg = "SSO component -- useSSO can't retrive SSO credential because SSOSite [" + SSOSite + "] doesn't exist";
      log.error(msg);
      SSOSite[] sites = new SSOSite[0];
      return this.getContentFromURL(proxyID, url, sites, bRefresh);
    }
     }
   
    /*
     *  (non-Javadoc)
     * @see org.apache.jetspeed.sso.SSOProvider#useSSO(java.lang.String, java.lang.String)
     */
    public String useSSO(Subject subject, String url, boolean bRefresh) throws SSOException
    {
      // Get the principal from the subject
    BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
    String fullPath = principal.getFullPath();

     
      /* ProxyID is used for the cache. The http client object will be cached for a
       * given user
       */
      String proxyID = fullPath;
     
      Collection sites = this.getSitesForPrincipal(fullPath);
     
      if (sites == null)
      {
        String msg = "SSO Component useSSO -- Couldn't find any SSO sites for user ["+fullPath+"]";
        log.error(msg);
        throw new SSOException(msg);
      }
     
      // Load all the sites
      int siteSize = sites.size();
      int siteIndex =0;
      SSOSite[] ssoSites = new SSOSite[siteSize];
     
      Iterator itSites = sites.iterator();
      while(itSites.hasNext())
      {
        SSOSite ssoSite = (SSOSite)itSites.next();
        if (ssoSite != null)
        {
          ssoSites[siteIndex] = ssoSite;
          siteIndex++;
        }
      }
     
      return this.getContentFromURL(proxyID, url, ssoSites, bRefresh);
    }
   
     /**
     * Retrive cookies for an user by User full path
     * @param fullPath
     * @return
     */
    public Collection getCookiesForUser(String fullPath)
    {
      // Get the SSO user identified by the fullPath
      SSOPrincipal ssoPrincipal = this.getSSOPrincipal(fullPath);
     
      // For each remote user we'll get the cookie
      Vector temp = new Vector();
     
      Iterator itRemotePrincipal = ssoPrincipal.getRemotePrincipals().iterator();
      while (itRemotePrincipal.hasNext())
      {
        InternalUserPrincipal rp  = (InternalUserPrincipal)itRemotePrincipal.next();
        if (rp != null)
        {
          temp.add(rp.getFullPath());
        }
      }
     
      if (temp.size() > 0)
      {
     
          Criteria filter = new Criteria();  
          filter.addIn("remotePrincipals.fullPath", temp);
          
          QueryByCriteria query = QueryFactory.newQuery(SSOCookieImpl.class, filter);
          return getPersistenceBrokerTemplate().getCollectionByQuery(query);
      }
      else
      {
        return null;
      }

    }
   
    /**
     * Retrive Cookies by Subject
     * @param user
     * @return
     */
    public Collection getCookiesForUser(Subject user)
    {
      // Get the principal from the subject
    BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(user, UserPrincipal.class);
    String fullPath = principal.getFullPath();
   
    // Call into API
    return this.getCookiesForUser(fullPath);
    }
   

    public void setRealmForSite(String site, String realm) throws SSOException
    {
      SSOSite ssoSite = getSSOSiteObject(site);
   
    if ( ssoSite != null)
    {
      try
      {
        ssoSite.setRealm(realm);
        getPersistenceBrokerTemplate().store(ssoSite);
      }
      catch (Exception e)
      {
        throw new SSOException("Failed to set the realm for site [" + site + "] Error" +e );
      }
    }
    }
   
    public String getRealmForSite(String site) throws SSOException
    {
      SSOSite ssoSite = getSSOSiteObject(site);
   
    if ( ssoSite != null)
    {
      return ssoSite.getRealm();
    }
   
    return null;
    }
   
    /**
     * Get all SSOSites that the principal has access to
     * @param userId
     * @return
     */
    public Collection getSitesForPrincipal(String fullPath)
    {
    
      Criteria filter = new Criteria();      
        filter.addEqualTo("principals.fullPath", fullPath);
       
        QueryByCriteria query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
        return getPersistenceBrokerTemplate().getCollectionByQuery(query);
    }
   
  public Iterator getSites(String filter)
    {
        Criteria queryCriteria = new Criteria();
        Query query = QueryFactory.newQuery(SSOSiteImpl.class, queryCriteria);
        Collection c = getPersistenceBrokerTemplate().getCollectionByQuery(query);
        return c.iterator();       
    }
 
  /**
     * addCredentialsForSite()
     * @param fullPath
     * @param remoteUser
     * @param site
     * @param pwd
     * @throws SSOException
     */
    public void addCredentialsForSite(String fullPath, String remoteUser, String site, String pwd) throws SSOException
    {
        // Create a Subject for the given path and forward it to the API addCredentialsForSite()
        Principal principal = null;
        String name = null;
       
        // Group or User
        if (fullPath.indexOf("/group/") > -1 )
        {
            name = fullPath.substring(GROUP_PATH.length());
            principal = new GroupPrincipalImpl(name);
        }
        else
        {
            name = fullPath.substring(USER_PATH.length());
            principal = new UserPrincipalImpl(name);
        }
        // Create Subject
        Set principals = new HashSet();
        principals.add(principal);
        Subject subject = new Subject(true, principals, new HashSet(), new HashSet())
       
        // Call into the API
        addCredentialsForSite(subject, remoteUser, site, pwd);
    }
   
    /**
     * removeCredentialsForSite()
     * @param fullPath
     * @param site
     * @throws SSOException
     */
    public void removeCredentialsForSite(String fullPath, String site) throws SSOException
    {
        // Create a Subject for the given path and forward it to the API addCredentialsForSite()
        Principal principal = null;
        String name = null;
       
        // Group or User
        if (fullPath.indexOf("/group/") > -1 )
        {
            name = fullPath.substring(GROUP_PATH.length());
            principal = new GroupPrincipalImpl(name);
        }
        else
        {
            name = fullPath.substring(USER_PATH.length());
            principal = new UserPrincipalImpl(name);
        }
        // Create Subject
        Set principals = new HashSet();
        principals.add(principal);
        Subject subject = new Subject(true, principals, new HashSet(), new HashSet())
   
        // Call into the API
        this.removeCredentialsForSite(subject,site);
    }
   
   
    /** Retrive site information
     *
     *  getSiteURL
     */
   
    public String getSiteURL(String site)
    {
        // The site is the URL
        return site;
    }
   
    /**
     * getSiteName
     */
    public String getSiteName(String site)
    {
        SSOSite ssoSite = getSSOSiteObject(site);
   
    if ( ssoSite != null)
    {
      return ssoSite.getName();
    }
    else
    {
        return null;
    }
    }
   
  /* (non-Javadoc)
   * @see org.apache.jetspeed.sso.SSOProvider#hasSSOCredentials(javax.security.auth.Subject, java.lang.String)
   */
  public boolean hasSSOCredentials(Subject subject, String site) {
    // Initialization
    SSOSite ssoSite = getSSOSiteObject(site);
   
    if ( ssoSite == null)
    {
      return false// no entry for site
    }
   
    // Get the principal from the subject
    BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
    String fullPath = principal.getFullPath();
   
       
    // Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
    Collection remoteForSite    = ssoSite.getRemotePrincipals();
    Collection principalsForSite  = ssoSite.getPrincipals()// Users
   
    // If any of them don't exist just return
    if (principalsForSite == null || remoteForSite== null )
        return false// no entry
   
    Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
   
    if ( remoteForPrincipals == null)
        return false// no entry
   
    // Get remote Principal that matches the site and the principal
    if (findRemoteMatch(remoteForPrincipals, remoteForSite) == null )
    {
        return false// No entry
    }
    else
    {
        return true// Has an entry
    }
  }

  /* (non-Javadoc)
   * @see org.apache.jetspeed.sso.SSOProvider#getCredentials(javax.security.auth.Subject, java.lang.String)
   */
  public SSOContext getCredentials(Subject subject, String site)
      throws SSOException {
   
    // Initialization
    SSOSite ssoSite = getSSOSiteObject(site);
   
    if ( ssoSite == null)
      throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE)// no entry for site
   
    // Get the principal from the subject
    BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
    String fullPath = principal.getFullPath();
   
    // Filter the credentials for the given principals
    SSOContext context = getCredential(ssoSite, fullPath)
   
    if ( context == null)
      throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE)// no entry for site
   
    return context;
  }

  /* addCredential()
     * Adds credentials for a user to the site. If the site doesn't exist it will be created
   * @see org.apache.jetspeed.sso.SSOProvider#addCredentialsForSite(javax.security.auth.Subject, java.lang.String, java.lang.String)
   */
  public void addCredentialsForSite(Subject subject, String remoteUser, String site, String pwd)
      throws SSOException {
   
    // Check if an entry for the site already exists otherwise create a new one
    SSOSite ssoSite = getSSOSiteObject(site);
    if (ssoSite == null)
    {
      // Create a new site
      ssoSite = new SSOSiteImpl();
      ssoSite.setSiteURL(site);
      ssoSite.setName(site);
      ssoSite.setCertificateRequired(false);
      ssoSite.setAllowUserSet(true);
      // By default we use ChallengeResponse Authentication
      ssoSite.setChallengeResponseAuthentication(true);
      ssoSite.setFormAuthentication(false);
     
      // Store the site so that we get a valid SSOSiteID
      try
           {
               getPersistenceBrokerTemplate().store(ssoSite);
            }
           catch (Exception e)
           {
             e.printStackTrace();
              throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
           }
    }
   
    // Get the Principal information (logged in user)
    String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
    String principalName = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getName();
   
    // Add an entry for the principal to the site if it doesn't exist
    SSOPrincipal principal = this.getPrincipalForSite(ssoSite, fullPath);
   
    if (principal == null )
    {
        principal = getSSOPrincipal(fullPath);
        ssoSite.addPrincipal(principal);
    }
    else
    {
        // Check if the entry the user likes to update exists already
        Collection remoteForSite = ssoSite.getRemotePrincipals();
        Collection principalsForSite = ssoSite.getPrincipals();
       
        if ( remoteForSite != null && principalsForSite != null)
        {
            Collection remoteForPrincipals = this.getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
            if ( remoteForPrincipals != null)
            {
              if (findRemoteMatch(remoteForPrincipals, remoteForSite) != null )
              {
                  // Entry exists can't to an add has to call update
                  throw new SSOException(SSOException.REMOTE_PRINCIPAL_EXISTS_CALL_UPDATE);
              }
            }
        }
    }
   
    if (principal == null)
      throw new SSOException(SSOException.FAILED_ADDING_PRINCIPAL_TO_MAPPING_TABLE_FOR_SITE);
   
    // Create a remote principal and credentials
    InternalUserPrincipalImpl remotePrincipal = new InternalUserPrincipalImpl(remoteUser);
   
    /*
     * The RemotePrincipal (class InternalUserPrincipal) will have a fullPath that identifies the entry as an SSO credential.
     * The entry has to be unique for a site and principal  (GROUP -or- USER ) an therefore it needs to be encoded as following:
     * The convention for the path is the following: /sso/SiteID/{user|group}/{user name | group name}/remote user name
     */
    if ( fullPath.indexOf("/group/") > -1)
        remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/group/"+  principalName + "/" + remoteUser);
    else
        remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/user/"+ principalName + "/" + remoteUser);
   
    // New credential object for remote principal
     InternalCredentialImpl credential =
            new InternalCredentialImpl(remotePrincipal.getPrincipalId(),
                this.scramble(pwd), 0, DefaultPasswordCredentialImpl.class.getName());
    
     if ( remotePrincipal.getCredentials() == null)
       remotePrincipal.setCredentials(new ArrayList(0));
    
    remotePrincipal.getCredentials().add( credential);
   
    // Add it to Principals remotePrincipals list
    principal.addRemotePrincipal(remotePrincipal);

    // Update the site remotePrincipals list
    ssoSite.getRemotePrincipals().add(remotePrincipal);
   
      
    // Update database and reset cache
     try
         {
             getPersistenceBrokerTemplate().store(ssoSite);
            
             // Persist Principal/Remote
         getPersistenceBrokerTemplate().store(principal);
          }
         catch (Exception e)
         {
           e.printStackTrace();
            throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
         }
        
         // Add to site
         this.mapSite.put(site, ssoSite);
  }

  /* (non-Javadoc)
   * @see org.apache.jetspeed.sso.SSOProvider#removeCredentialsForSite(javax.security.auth.Subject, java.lang.String)
   */
  public void removeCredentialsForSite(Subject subject, String site)
      throws SSOException {
   
    // Initailization
    InternalUserPrincipal remotePrincipal = null;
    //Get the site
    SSOSite ssoSite = getSSOSiteObject(site);
    if (ssoSite == null)
    {
      throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
    }
   
    // Get the Principal information
    String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
   
    try
    {
      //  Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
      Collection principalsForSite = ssoSite.getPrincipals();
      Collection remoteForSite = ssoSite.getRemotePrincipals();
     
      // If any of them don't exist just return
      if (principalsForSite == null || remoteForSite== null )
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
     
      Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
     
      if ( remoteForPrincipals == null)
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
     
      // Get remote Principal that matches the site and the principal
      if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
      {
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
      }

      // Update assocation tables
      ssoSite.getRemotePrincipals().remove(remotePrincipal);
     
      if (remoteForPrincipals.remove(remotePrincipal) == true)
     
      // Update the site
      getPersistenceBrokerTemplate().store(ssoSite);

      // delete the remote Principal from the SECURITY_PRINCIPAL table
        getPersistenceBrokerTemplate().delete(remotePrincipal);
       
           
    }
    catch(SSOException ssoex)
    {
      throw new SSOException(ssoex);
    }
    catch (Exception e)
        {
          e.printStackTrace();
           throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
        }
               
    // Update database
     try
         {
             getPersistenceBrokerTemplate().store(ssoSite);
          }
         catch (Exception e)
         {
           e.printStackTrace();
            throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
         }
        
  }
 
  /**
   * updateCredentialsForSite
   * @param subject  Current subject
   * @param remoteUser  remote user login
   * @param site    URL or description of site
   * @param pwd  Password for credentail
   */
  public void  updateCredentialsForSite(Subject subject, String remoteUser, String site, String pwd
      throws SSOException
      {
          // Check if the the current user has a credential for the site
   
      // Update the credential
      //     Initailization
      InternalUserPrincipal remotePrincipal = null;
     
      //Get the site
      SSOSite ssoSite = getSSOSiteObject(site);
      if (ssoSite == null)
      {
        throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
      }
     
      // Get the Principal information
      String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
     
      //  Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
      Collection principalsForSite  = ssoSite.getPrincipals();
      Collection remoteForSite    = ssoSite.getRemotePrincipals();
     
      // If any of them don't exist just return
      if (principalsForSite == null || remoteForSite== null )
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
     
      Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
     
      if ( remoteForPrincipals == null)
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
     
      // Get remote Principal that matches the site and the principal
      if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
      {
          throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
      }
           
      // Update principal information
      //remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/user/"+ principalName + "/" + remoteUser);
     
      InternalCredential credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
         
      // New credential object
       if ( credential != null)
        // Remove credential and principal from mapping
         credential.setValue(this.scramble(pwd));
     
      // Update database and reset cache
       try
       {
           getPersistenceBrokerTemplate().store(credential);
        }
       catch (Exception e)
       {
         e.printStackTrace();
          throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
       }      
      }
 
  /*
   * Helper utilities
   *
   */
 
  /*
   * getSSOSiteObject
   * Obtains the Site information including the credentials for a site (url).
   */
 
  private SSOSite getSSOSiteObject(String site)
  {
    //Initialization
    SSOSite ssoSite = null;
   
    //Check if the site is in the map
    if (mapSite.containsKey(site) == false )
    {
      //  Go to the database and fetch the information for this site
      //  Find the MediaType by matching the Mimetype
               
        Criteria filter = new Criteria();      
        filter.addEqualTo("siteURL", site);
       
        QueryByCriteria query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
        Collection ssoSiteCollection = getPersistenceBrokerTemplate().getCollectionByQuery(query);                   
       
        if ( ssoSiteCollection != null && ssoSiteCollection.isEmpty() != true)
        {
          Iterator itSite = ssoSiteCollection.iterator();
          // Get the site from the collection. There should be only one entry (uniqueness)
          if (itSite.hasNext())
          {
              ssoSite = (SSOSite) itSite.next();
          }
         
          // Add it to the map
          mapSite.put(site, ssoSite);
        }
        else
        {
          // No entry for this site
          return null;
        }
    }
    else
    {
      ssoSite = (SSOSite)mapSite.get(site);
    }
   
    return ssoSite;
  }
 
  /*
   * getCredential
   * returns the credentials for a given user
   */
  private SSOContext  getCredential(SSOSite ssoSite, String fullPath)
  {
    InternalCredential credential = null;
    InternalUserPrincipal remotePrincipal = null;
    //  Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
    Collection principalsForSite = ssoSite.getPrincipals();
    Collection remoteForSite = ssoSite.getRemotePrincipals();
   
    // If any of them don't exist just return
    if ( principalsForSite == null  || remoteForSite== null )
        return null// no entry
   
    Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
       
    if ( remoteForPrincipals == null)
        return null// no entry
   
    // Get remote Principal that matches the site and the principal
    if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
    {
        return null// No entry
    }
    else
    {
        // Has an entry
      if ( remotePrincipal.getCredentials() != null)
        credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
     
      // Error checking  -- should have a credential at this point
      if ( credential == null)
      {
//        System.out.println("Warning: Remote User " + remotePrincipal.getFullPath() + " doesn't have a credential");
        return null;
      }
    }
   
    //  Create new context
    String name = stripPrincipalName(remotePrincipal.getFullPath());
   
    SSOContext context = new SSOContextImpl(credential.getPrincipalId(), name, this.unscramble(credential.getValue()));
   
    return context;
  }
 
    private String stripPrincipalName(String fullPath)
    {
        String name;
        int ix = fullPath.lastIndexOf('/');
        if ( ix != -1)
            name = fullPath.substring(ix + 1);
        else
            name = new String(fullPath);
       
        return name;       
    }

  /*
   * Get a Collection of remote Principals for the logged in principal identified by the full path
   *   
  private Collection getRemotePrincipalsForPrincipal(SSOSite ssoSite, String fullPath)
  {
    // The site orincipals list contains a list of remote principals for the user
    Collection principals = ssoSite.getPrincipals();
   
    if ( principals == null )
      return null;  // No principals for this site
   
    Iterator ixPrincipals = principals.iterator();
    while (ixPrincipals.hasNext())
    {
      SSOPrincipal principal = (SSOPrincipal)ixPrincipals.next();
      if (         principal != null
              && principal.getFullPath().compareToIgnoreCase(fullPath) == 0 )
      {
        // Found Principal -- extract remote principals
        return principal.getRemotePrincipals();
      }
    }
   
    // Principal is not in list
    return null;
  }
    */
 
  /*
   * getPrincipalForSite()
   * returns a principal that matches the full path for the site or creates a new entry if it doesn't exist
   */
  private SSOPrincipal getPrincipalForSite(SSOSite ssoSite, String fullPath)
  {
    SSOPrincipal principal = null;
    Collection principalsForSite = ssoSite.getPrincipals();
   
    if ( principalsForSite != null)
    {
      Iterator itPrincipals = principalsForSite.iterator();
      while (itPrincipals.hasNext() && principal == null)
      {
        SSOPrincipal tmp  = (SSOPrincipal)itPrincipals.next();
        if (      tmp != null
               && tmp.getFullPath().compareToIgnoreCase(fullPath) == 0 )
          principal = tmp;  // Found existing entry
      }
    }
   
    return principal;
  }
 
  private SSOPrincipal getSSOPrincipal(String fullPath)
  {
      // FInd if the principal exists in the SECURITY_PRINCIPAL table
      SSOPrincipal principal = null;
     
    Criteria filter = new Criteria();      
      filter.addEqualTo("fullPath", fullPath);
     
      QueryByCriteria query = QueryFactory.newQuery(SSOPrincipalImpl.class, filter);
      Collection principals = getPersistenceBrokerTemplate().getCollectionByQuery(query);                   
     
      if ( principals != null && principals.isEmpty() != true)
      {
        Iterator itPrincipals = principals.iterator();
        // Get the site from the collection. There should be only one entry (uniqueness)
        if (itPrincipals.hasNext())
        {
          principal = (SSOPrincipal) itPrincipals.next();
        }
      }
     
    return principal;   
  }
 
 
 
  /**
   * removeRemotePrincipalForPrincipal
   * @param site
   * @param fullPath
   * @return
   *
   * removes remotePrincipal for a site & principal
   *
  private InternalUserPrincipal  removeRemotePrincipalForPrincipal(SSOSite site, String fullPath) throws SSOException
  {
    if (site.getPrincipals() != null)
    {
      Iterator itPrincipals = site.getPrincipals().iterator();
      while (itPrincipals.hasNext())
      {
        SSOPrincipal tmp = (SSOPrincipal)itPrincipals.next();
        if (tmp.getFullPath().compareToIgnoreCase(fullPath) == 0)
        {
          // Found -- get the remotePrincipal
          Collection collRemotePrincipals = tmp.getRemotePrincipals() ;
          if (collRemotePrincipals != null)
          {
         
            Iterator itRemotePrincipals = collRemotePrincipals.iterator();
            if  (itRemotePrincipals.hasNext())
            {
              InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)itRemotePrincipals.next();
              // Found remove the object
              collRemotePrincipals.remove(remotePrincipal);
              return remotePrincipal;
            }
          }
        }
      }
    }   
   
    throw new SSOException(SSOException.REQUESTED_PRINCIPAL_DOES_NOT_EXIST);
  }
  */
   
  /*
   *
   *
   */
  private InternalUserPrincipal findRemoteMatch(Collection remoteForPrincipals, Collection remoteForSite)
  {
      // Iterate over the lists and find match
      Iterator itRemoteForPrincipals = remoteForPrincipals.iterator();
      while ( itRemoteForPrincipals.hasNext())
      {
          InternalUserPrincipal remoteForPrincipal = (InternalUserPrincipal)itRemoteForPrincipals.next();
         
          // Find a match in the site list
          Iterator itRemoteForSite = remoteForSite.iterator();
        while ( itRemoteForSite.hasNext())
        {
            InternalUserPrincipal tmp = (InternalUserPrincipal)itRemoteForSite.next();
           
            if ( tmp.getPrincipalId() == remoteForPrincipal.getPrincipalId() )
                return remoteForPrincipal;
        }
      }
      // No match found
      return null;
  }
 
  /*
   * getRemotePrincipalsForPrincipals
   * Checks if the user has any remote principals. If the principal is a group expand the group and
   * check if the requesting user is a part of the group.
   */
  private Collection getRemotePrincipalsForPrincipal(Collection principalsForSite, String fullPath)
  {
      if (principalsForSite != null )
      {
        Iterator itPrincipalsForSite = principalsForSite.iterator();
        while (itPrincipalsForSite.hasNext())
        {
            String principalFullPath = null;
            SSOPrincipal principal = (SSOPrincipal)itPrincipalsForSite.next();
            principalFullPath = principal.getFullPath();
           
            /* If the Principal is for a Group expand the Group and check if the user identified
            * by the fullPath is a member of the Group. If the user is a member of the Group
            * return the remote Credentials for the current Principal.
            */
            if ( principalFullPath.indexOf("/group/") == -1)
            {
                // USER
                if ( principalFullPath.compareToIgnoreCase(fullPath) == 0)
                    return principal.getRemotePrincipals();
            }
            else
            {
                /* GROUP
                 * If the full path is for a group (delete/add) just return the the list of remotePrincipals
                 * For a lookup (hasCredentials) the user needs to be mapped against each member of the group
                */
                if ( principalFullPath.compareToIgnoreCase(fullPath) == 0)
                    return principal.getRemotePrincipals();
               
                /* Expand the Group and find a match */
              InternalGroupPrincipal  groupPrincipal = getGroupPrincipals(principalFullPath);
             
              // Found Group that matches the name
              if (groupPrincipal != null)
                {
                  Collection usersInGroup = groupPrincipal.getUserPrincipals();
                  Iterator itUsers = usersInGroup.iterator();
                    while (itUsers.hasNext())
                    {
                        InternalUserPrincipal user = (InternalUserPrincipal)itUsers.next();
                        if (user.getFullPath().compareToIgnoreCase(fullPath) == 0)
                        {
                            // User is member of the group
                            return principal.getRemotePrincipals();
                        }
                    }
                }
            } 
        }
      }
     
      // No match found
      return null;
  }
   
    public SSOSite getSite(String siteUrl)
    {
        Criteria filter = new Criteria();
        filter.addEqualTo("url", siteUrl);
        Query query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
        SSOSite site = (SSOSite) getPersistenceBrokerTemplate().getObjectByQuery(query);
        return site;      
    }
   
    public void updateSite(SSOSite site)
    throws SSOException
    {
        try
        {
            getPersistenceBrokerTemplate().store(site);
            this.mapSite.put(site.getName(), site);                       
        }
        catch (Exception e)
        {
            String msg = "Unable to remove SSO Site: " + site.getName();
            logger.error(msg, e);
            throw new SSOException(msg, e);
        }       
    }
   
    /**
     * Add a new site that uses Form Authentication
     * @param siteName
     * @param siteUrl
     * @param realm
     * @param userField
     * @param pwdField
     * @throws SSOException
     */
    public void addSiteFormAuthenticated(String siteName, String siteUrl, String realm, String userField, String pwdField)
    throws SSOException
    {
      try
        {
            SSOSite ssoSite = new SSOSiteImpl();
            ssoSite.setSiteURL(siteUrl);
            ssoSite.setName(siteName);
            ssoSite.setCertificateRequired(false);
            ssoSite.setAllowUserSet(true);
            ssoSite.setRealm(realm);
            ssoSite.setFormAuthentication(true);
            ssoSite.setFormUserField(userField);
            ssoSite.setFormPwdField(pwdField);
            getPersistenceBrokerTemplate().store(ssoSite);
            this.mapSite.put(siteName, ssoSite);           
        }
        catch (Exception e)
        {
            String msg = "Unable to add SSO Site: " + siteName;
            logger.error(msg, e);
            throw new SSOException(msg, e);
       
    }
   
    /**
     * Add a new site that uses ChallengeResponse Authentication
     * @param siteName
     * @param siteUrl
     * @param realm
     * @throws SSOException
     */
    public void addSiteChallengeResponse(String siteName, String siteUrl, String realm)
    throws SSOException
    {
      try
        {
            SSOSite ssoSite = new SSOSiteImpl();
            ssoSite.setSiteURL(siteUrl);
            ssoSite.setName(siteName);
            ssoSite.setCertificateRequired(false);
            ssoSite.setAllowUserSet(true);
            ssoSite.setRealm(realm);
            ssoSite.setChallengeResponseAuthentication(true);
             getPersistenceBrokerTemplate().store(ssoSite);
            this.mapSite.put(siteName, ssoSite);           
        }
        catch (Exception e)
        {
            String msg = "Unable to add SSO Site: " + siteName;
            logger.error(msg, e);
            throw new SSOException(msg, e);
       
    }
   
    public void addSite(String siteName, String siteUrl)
    throws SSOException
    {
        try
        {
            SSOSite ssoSite = new SSOSiteImpl();
            ssoSite.setSiteURL(siteUrl);
            ssoSite.setName(siteName);
            ssoSite.setCertificateRequired(false);
            ssoSite.setAllowUserSet(true);           
            getPersistenceBrokerTemplate().store(ssoSite);
            this.mapSite.put(siteName, ssoSite);           
        }
        catch (Exception e)
        {
            String msg = "Unable to remove SSO Site: " + siteName;
            logger.error(msg, e);
            throw new SSOException(msg, e);
        }               
    }
   
    public void removeSite(SSOSite site)
    throws SSOException
    {
        try
        {
            getPersistenceBrokerTemplate().delete(site);
            this.mapSite.remove(site);

        }
        catch (Exception e)
        {
            String msg = "Unable to remove SSO Site: " + site.getName();
            logger.error(msg, e);
            throw new SSOException(msg, e);
        }       
    }
       
    public List getPrincipalsForSite(SSOSite site)
    {
        List list = new ArrayList();
        Iterator principals = site.getRemotePrincipals().iterator();
        while (principals.hasNext())
        {
            InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)principals.next();
            Iterator creds = remotePrincipal.getCredentials().iterator();
            while (creds.hasNext())
            {
                InternalCredential cred = (InternalCredential) creds.next();
                SSOContext context = new SSOContextImpl(remotePrincipal.getPrincipalId(),
                                                stripPrincipalName(remotePrincipal.getFullPath()),
                                                cred.getValue(),
                                                stripPortalPrincipalName(remotePrincipal.getFullPath()));
                list.add(context);
            }
        }
        return list;
    }

   
    private String stripPortalPrincipalName(String fullPath)
    {
        StringTokenizer tokenizer = new StringTokenizer(fullPath, "/");
        while (tokenizer.hasMoreTokens())
        {
            String token = tokenizer.nextToken();
            if (token.equals("user") || token.equals("group"))
            {
                 if (tokenizer.hasMoreTokens())
                {
                    return tokenizer.nextToken();
                }
            }
        }
        return fullPath;       
    }
   
    private InternalGroupPrincipal  getGroupPrincipals(String principalFullPath)
    {
        // Get to the backend to return the group that matches the full path
        Criteria filter = new Criteria();
        filter.addEqualTo("fullPath", principalFullPath);
        Query query = QueryFactory.newQuery(InternalGroupPrincipalImpl.class, filter);
        InternalGroupPrincipal group = (InternalGroupPrincipal) getPersistenceBrokerTemplate().getObjectByQuery(query);
        return group;      
    }
   
    /*
    private SSOSite getSiteForRemoteUser(String fullPath)
    {
      // Get Site for remote user
        Criteria filter = new Criteria();
        filter.addEqualTo("remotePrincipals.fullPath", fullPath);
        Query query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
        return  (SSOSite) getPersistenceBrokerTemplate().getObjectByQuery(query);
    }
    */
   
    private String getContentFromURL(String proxyID, String destUrl, SSOSite[] sites, boolean bRefresh ) throws SSOException
    {
      URL urlObj = null;
     
      // Result Buffer
      //BufferedInputStream bis = null;
      String resultPage;
     
      String strErrorMessage = "SSO Component Error. Failed to get content for URL " + destUrl;
     
      try
      {
        urlObj = new URL(destUrl);
      }
      catch (MalformedURLException e)
      {
        String msg = ("Error -- Malformed URL [" + destUrl +"] for SSO authenticated destination");
        log.error(msg);
        throw new SSOException(msg, e);
      }
     
      /*
       * Setup HTTPClient
       * Check if an HTTP Client already exists for the given /user/site
       */
      HttpClient client = (HttpClient)this.clientProxy.get(proxyID);
      GetMethod get = null;
     
      if (bRefresh == true || client == null)
      {
        if (log.isInfoEnabled())
          log.info("SSO Component -- Create new HTTP Client object for Principal/URL [" + proxyID+ "]");
       
        client = new HttpClient();
        client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
       
        int numberOfSites = sites.length;
       
        // Do all the logins for the site
        for (int i=0; i<numberOfSites; i++)
        {
          SSOSite site = sites[i];
         
          if (site != null)
          {
            Iterator itRemotePrincipals = site.getRemotePrincipals().iterator();
            while (itRemotePrincipals.hasNext() )
            {
              InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)itRemotePrincipals.next();
                  if (remotePrincipal != null)
                  {
                    InternalCredential credential = null;
                    if ( remotePrincipal.getCredentials() != null)
                      credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
                   
                    if (credential != null)
                    {
                      if (log.isInfoEnabled())
                        log.info("SSOComponent -- Remote Principal ["+stripPrincipalName(remotePrincipal.getFullPath())+"] has credential ["+this.unscramble(credential.getValue())+ "]");
                     
                      client.getState().setCredentials(
                            site.getRealm(),
                                  urlObj.getHost(),
                                  new UsernamePasswordCredentials(stripPrincipalName(remotePrincipal.getFullPath())this.unscramble(credential.getValue()))
                              );
                     
                      // Build URL if it's Form authentication
                      StringBuffer siteURL = new StringBuffer(site.getSiteURL());
                    
                    // Check if it's form based or ChallengeResponse
                    if (site.isFormAuthentication())
                    {
                      siteURL.append("?").append(site.getFormUserField()).append("=").append(stripPrincipalName(remotePrincipal.getFullPath())).append("&").append(site.getFormPwdField()).append("=").append(this.unscramble(credential.getValue()));
                    }
                     
                      get = new GetMethod(siteURL.toString());
 
                            // Tell the GET method to automatically handle authentication. The
                            // method will use any appropriate credentials to handle basic
                            // authentication requests.  Setting this value to false will cause
                            // any request for authentication to return with a status of 401.
                            // It will then be up to the client to handle the authentication.
                            get.setDoAuthentication( true );
                            try {
                                // execute the GET
                                int status = client.executeMethod( get );
                               
                                if (log.isInfoEnabled() )
                                    log.info("Accessing site [" + site.getSiteURL() + "]. HTTP Status [" +status+ "]" );
                               
                                /*
                             * If the destination URL and the SSO url match
                             * use the authentication process but return immediately
                             * the result page.
                             */
                                if( destUrl.compareTo(site.getSiteURL()) == 0 && numberOfSites == 1)
                                {
                                  if (log.isInfoEnabled() )
                                    log.info("SSO Component --SSO Site and destination URL match. Go and get the content." );
                                 
                                  //try
                                //{
                                  //bis = new BufferedInputStream(get.getResponseBodyAsStream());
                                  resultPage = get.getResponseBodyAsString();
                                //}
                                //catch(IOException ioe)
                                //{
                                //  log.error(strErrorMessage, ioe);
                                //  throw new SSOException (strErrorMessage, ioe); 
                                //}

                                get.releaseConnection();
                               
                                //  Add the client object to the cache
                                this.clientProxy.put(proxyID, client);
                               
                                //return bis;
                                return resultPage;
                                }
                       
                      } catch (Exception e) {
                              log.error("Exception while authentication. Error: " +e);                         
                            }
                     
                      get.releaseConnection();
                     }
                  }
            }
          }      
        }
       
        // Add the client object to the cache
        this.clientProxy.put(proxyID, client);
      }
      else
      {
        if (log.isInfoEnabled())
          log.info("SSO Component -- Use cached HTTP Client object for Principal/URL [" + proxyID+ "]");
      }
     
      // All the SSO authentication done go to the destination url
    get = new GetMethod(destUrl);
    try {
            // execute the GET
            int status = client.executeMethod( get );
           
            log.info("Accessing site [" + destUrl + "]. HTTP Status [" +status+ "]" );
   
    } catch (Exception e) {
          log.error("Exception while authentication. Error: " +e);                         
        }
   
   
    try
    {
      //bis = new BufferedInputStream(get.getResponseBodyAsStream());
      resultPage = get.getResponseBodyAsString();
    }
    catch(IOException ioe)
    {
      log.error(strErrorMessage, ioe);
      throw new SSOException (strErrorMessage, ioe);
        }
    catch (Exception e)
    {
      log.error(strErrorMessage, e);
      throw new SSOException (strErrorMessage, e);
     
    }
        finally
        {
            get.releaseConnection();
        }
   
    //return bis;
    return resultPage;
    }
   
    /*
     * Simple encryption decryption routines since the API creates credentials
     * together with an user.
     * TODO: re-implement when Security API is more flexible
     */
    static char[] scrambler ="Jestspeed-2 is getting ready for release".toCharArray();
   
    private String scramble(String pwd)
    {
        // xor-ing persistent String values is dangerous because of the (uncommon) way Java encodes UTF-8 0x00 (and some other characters).
        // See: http://en.wikipedia.org/wiki/UTF-8#Java
        // On some database platforms, like PostgreSQL this can lead to something like:
        //   org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
        // To prevent this, the resulting xored password is encoded in Base64
      String xored = new String(xor(pwd.toCharArray(), scrambler));
        byte[] bytes = Base64.encodeBase64(xored.getBytes());
        String scrambled = new String(bytes);
        return scrambled;
    }
   
    private String unscramble(String pwd)
    {
      byte[] bytes = pwd.getBytes();
        bytes = Base64.decodeBase64(bytes);
        String chars = new String(bytes);
        String unscrambled = new String(xor(chars.toCharArray(), scrambler));
        return unscrambled;
    }
   
    private char[] xor(char[] a, char[]b)
    {
      int len = Math.min(a.length, b.length);
      char[] result = new char[len];
      for(int i=0; i<len;i++)
      {
        result[i] = (char) (a[i] ^ b[i]);
      }
      return result;
    }
}
TOP

Related Classes of org.apache.jetspeed.sso.impl.PersistenceBrokerSSOProvider

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.