View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.sso.impl;
18  
19  import java.io.IOException;
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  import java.security.Principal;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.HashSet;
26  import java.util.Hashtable;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Set;
30  import java.util.StringTokenizer;
31  import java.util.Vector;
32  
33  import javax.security.auth.Subject;
34  
35  import org.apache.commons.codec.binary.Base64;
36  import org.apache.commons.httpclient.HttpClient;
37  import org.apache.commons.httpclient.UsernamePasswordCredentials;
38  import org.apache.commons.httpclient.cookie.CookiePolicy;
39  import org.apache.commons.httpclient.methods.GetMethod;
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  import org.apache.jetspeed.components.dao.InitablePersistenceBrokerDaoSupport;
43  import org.apache.jetspeed.security.BasePrincipal;
44  import org.apache.jetspeed.security.SecurityHelper;
45  import org.apache.jetspeed.security.UserPrincipal;
46  import org.apache.jetspeed.security.impl.GroupPrincipalImpl;
47  import org.apache.jetspeed.security.impl.UserPrincipalImpl;
48  import org.apache.jetspeed.security.om.InternalCredential;
49  import org.apache.jetspeed.security.om.InternalGroupPrincipal;
50  import org.apache.jetspeed.security.om.InternalUserPrincipal;
51  import org.apache.jetspeed.security.om.impl.InternalCredentialImpl;
52  import org.apache.jetspeed.security.om.impl.InternalGroupPrincipalImpl;
53  import org.apache.jetspeed.security.om.impl.InternalUserPrincipalImpl;
54  import org.apache.jetspeed.security.spi.impl.DefaultPasswordCredentialImpl;
55  import org.apache.jetspeed.sso.SSOContext;
56  import org.apache.jetspeed.sso.SSOException;
57  import org.apache.jetspeed.sso.SSOPrincipal;
58  import org.apache.jetspeed.sso.SSOProvider;
59  import org.apache.jetspeed.sso.SSOSite;
60  import org.apache.ojb.broker.query.Criteria;
61  import org.apache.ojb.broker.query.Query;
62  import org.apache.ojb.broker.query.QueryByCriteria;
63  import org.apache.ojb.broker.query.QueryFactory;
64  
65  
66  /***
67  * <p>Utility component to handle SSO requests</p>
68  * 
69  * @author <a href="mailto:rogerrut@apache.org">Roger Ruttimann</a>
70  */
71  public class PersistenceBrokerSSOProvider extends
72  		InitablePersistenceBrokerDaoSupport implements SSOProvider 
73  {	
74  	/* Logging */
75  	private static final Log log = LogFactory.getLog(PersistenceBrokerSSOProvider.class);
76  	
77  	/*
78  	 * Cache for sites and Proxy sites
79  	 */
80  	private Hashtable mapSite = new Hashtable();
81  	private Hashtable clientProxy = new Hashtable();
82  	
83      private String USER_PATH = "/user/";
84      private String GROUP_PATH = "/group/";
85  
86    	/***
87       * PersitenceBrokerSSOProvider()
88       * @param repository Location of repository mapping file.  Must be available within the classpath.
89       * @param prefsFactoryImpl <code>java.util.prefs.PreferencesFactory</code> implementation to use.
90       * @param enablePropertyManager  Whether or not we chould be suing the property manager.
91       * @throws ClassNotFoundException if the <code>prefsFactoryImpl</code> argument does not reperesent
92       * a Class that exists in the current classPath.
93       */
94      public PersistenceBrokerSSOProvider(String repositoryPath) throws ClassNotFoundException
95      {
96         super(repositoryPath);
97      }
98      
99      
100     /*
101      *  (non-Javadoc)
102      * @see org.apache.jetspeed.sso.SSOProvider#useSSO(java.lang.String, java.lang.String, java.lang.String)
103      */
104     public String useSSO(Subject subject, String url, String SSOSite, boolean bRefresh) throws SSOException
105     {
106     	// Get the principal from the subject
107 		BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
108 		String fullPath = principal.getFullPath();
109 		
110     	/* ProxyID is used for the cache. The http client object will be cached for a
111     	 * given user site url combination
112     	 */
113     	String proxyID = fullPath + "_" + SSOSite;
114     	
115     	// Get the site
116     	SSOSite ssoSite = getSSOSiteObject(SSOSite);
117 		
118 		if ( ssoSite != null)
119 		{
120 			SSOSite[] sites = new SSOSite[1];
121 			sites[0] = ssoSite;
122 			
123 			return this.getContentFromURL(proxyID, url, sites, bRefresh);
124 		}
125 		else
126 		{
127 			// Site doesn't exist -- log an error but continue
128 			String msg = "SSO component -- useSSO can't retrive SSO credential because SSOSite [" + SSOSite + "] doesn't exist";
129 			log.error(msg);
130 			SSOSite[] sites = new SSOSite[0];
131 			return this.getContentFromURL(proxyID, url, sites, bRefresh);
132 		}
133      }
134     
135     /*
136      *  (non-Javadoc)
137      * @see org.apache.jetspeed.sso.SSOProvider#useSSO(java.lang.String, java.lang.String)
138      */
139     public String useSSO(Subject subject, String url, boolean bRefresh) throws SSOException
140     {
141     	// Get the principal from the subject
142 		BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
143 		String fullPath = principal.getFullPath();
144 
145     	
146     	/* ProxyID is used for the cache. The http client object will be cached for a
147     	 * given user 
148     	 */
149     	String proxyID = fullPath;
150     	
151     	Collection sites = this.getSitesForPrincipal(fullPath);
152     	
153     	if (sites == null)
154     	{
155     		String msg = "SSO Component useSSO -- Couldn't find any SSO sites for user ["+fullPath+"]";
156     		log.error(msg);
157     		throw new SSOException(msg);
158     	}
159     	
160     	// Load all the sites
161     	int siteSize = sites.size();
162     	int siteIndex =0;
163     	SSOSite[] ssoSites = new SSOSite[siteSize];
164     	
165     	Iterator itSites = sites.iterator();
166     	while(itSites.hasNext())
167     	{
168     		SSOSite ssoSite = (SSOSite)itSites.next();
169     		if (ssoSite != null)
170     		{
171     			ssoSites[siteIndex] = ssoSite;
172     			siteIndex++;
173     		}
174     	}
175     	
176     	return this.getContentFromURL(proxyID, url, ssoSites, bRefresh);
177     }
178     
179      /***
180      * Retrive cookies for an user by User full path
181      * @param fullPath
182      * @return
183      */
184     public Collection getCookiesForUser(String fullPath)
185     {
186     	// Get the SSO user identified by the fullPath
187     	SSOPrincipal ssoPrincipal = this.getSSOPrincipal(fullPath);
188     	
189     	// For each remote user we'll get the cookie
190     	Vector temp = new Vector();
191     	
192     	Iterator itRemotePrincipal = ssoPrincipal.getRemotePrincipals().iterator();
193     	while (itRemotePrincipal.hasNext())
194     	{
195     		InternalUserPrincipal rp  = (InternalUserPrincipal)itRemotePrincipal.next();
196     		if (rp != null)
197     		{
198     			temp.add(rp.getFullPath());
199     		}
200     	}
201     	
202     	if (temp.size() > 0)
203     	{
204     	
205 	        Criteria filter = new Criteria();   
206 	        filter.addIn("remotePrincipals.fullPath", temp);
207 	         
208 	        QueryByCriteria query = QueryFactory.newQuery(SSOCookieImpl.class, filter);
209 	        return getPersistenceBrokerTemplate().getCollectionByQuery(query);
210     	}
211     	else
212     	{
213     		return null;
214     	}
215 
216     }
217     
218     /***
219      * Retrive Cookies by Subject
220      * @param user
221      * @return
222      */
223     public Collection getCookiesForUser(Subject user)
224     {
225     	// Get the principal from the subject
226 		BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(user, UserPrincipal.class);
227 		String fullPath = principal.getFullPath();
228 		
229 		// Call into API
230 		return this.getCookiesForUser(fullPath);
231     }
232     
233 
234     public void setRealmForSite(String site, String realm) throws SSOException
235     {
236     	SSOSite ssoSite = getSSOSiteObject(site);
237 		
238 		if ( ssoSite != null)
239 		{
240 			try
241 			{
242 				ssoSite.setRealm(realm);
243 				getPersistenceBrokerTemplate().store(ssoSite);
244 			}
245 			catch (Exception e)
246 			{
247 				throw new SSOException("Failed to set the realm for site [" + site + "] Error" +e );
248 			}
249 		}
250     }
251     
252     public String getRealmForSite(String site) throws SSOException
253     {
254     	SSOSite ssoSite = getSSOSiteObject(site);
255 		
256 		if ( ssoSite != null)
257 		{
258 			return ssoSite.getRealm();
259 		}
260 		
261 		return null;
262     }
263     
264     /***
265      * Get all SSOSites that the principal has access to
266      * @param userId
267      * @return
268      */
269     public Collection getSitesForPrincipal(String fullPath)
270     {
271    	
272     	Criteria filter = new Criteria();       
273         filter.addEqualTo("principals.fullPath", fullPath);
274         
275         QueryByCriteria query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
276         return getPersistenceBrokerTemplate().getCollectionByQuery(query); 
277     }
278     
279 	public Iterator getSites(String filter)
280     {
281         Criteria queryCriteria = new Criteria();
282         Query query = QueryFactory.newQuery(SSOSiteImpl.class, queryCriteria);
283         Collection c = getPersistenceBrokerTemplate().getCollectionByQuery(query);
284         return c.iterator();        
285     }
286 	
287 	/***
288      * addCredentialsForSite()
289      * @param fullPath
290      * @param remoteUser
291      * @param site
292      * @param pwd
293      * @throws SSOException
294      */
295     public void addCredentialsForSite(String fullPath, String remoteUser, String site, String pwd) throws SSOException
296     {
297         // Create a Subject for the given path and forward it to the API addCredentialsForSite()
298         Principal principal = null;
299         String name = null;
300         
301         // Group or User
302         if (fullPath.indexOf("/group/") > -1 )
303         {
304             name = fullPath.substring(GROUP_PATH.length());
305             principal = new GroupPrincipalImpl(name);
306         }
307         else
308         {
309             name = fullPath.substring(USER_PATH.length());
310             principal = new UserPrincipalImpl(name);
311         }
312  
313         // Create Subject
314         Set principals = new HashSet();
315         principals.add(principal);
316         Subject subject = new Subject(true, principals, new HashSet(), new HashSet());	
317         
318         // Call into the API
319         addCredentialsForSite(subject, remoteUser, site, pwd);
320     }
321     
322     /***
323      * removeCredentialsForSite()
324      * @param fullPath
325      * @param site
326      * @throws SSOException
327      */
328     public void removeCredentialsForSite(String fullPath, String site) throws SSOException
329     {
330         // Create a Subject for the given path and forward it to the API addCredentialsForSite()
331         Principal principal = null;
332         String name = null;
333         
334         // Group or User
335         if (fullPath.indexOf("/group/") > -1 )
336         {
337             name = fullPath.substring(GROUP_PATH.length());
338             principal = new GroupPrincipalImpl(name);
339         }
340         else
341         {
342             name = fullPath.substring(USER_PATH.length());
343             principal = new UserPrincipalImpl(name);
344         }
345  
346         // Create Subject
347         Set principals = new HashSet();
348         principals.add(principal);
349         Subject subject = new Subject(true, principals, new HashSet(), new HashSet());	
350     
351         // Call into the API
352         this.removeCredentialsForSite(subject,site);
353     }
354     
355     
356     /*** Retrive site information
357      * 
358      *  getSiteURL
359      */
360     
361     public String getSiteURL(String site)
362     {
363         // The site is the URL
364         return site;
365     }
366     
367     /***
368      * getSiteName
369      */
370     public String getSiteName(String site)
371     {
372         SSOSite ssoSite = getSSOSiteObject(site);
373 		
374 		if ( ssoSite != null)
375 		{
376 			return ssoSite.getName();
377 		}
378 		else
379 		{
380 		    return null;
381 		}
382     }
383     
384 	/* (non-Javadoc)
385 	 * @see org.apache.jetspeed.sso.SSOProvider#hasSSOCredentials(javax.security.auth.Subject, java.lang.String)
386 	 */
387 	public boolean hasSSOCredentials(Subject subject, String site) {
388 		// Initialization
389 		SSOSite ssoSite = getSSOSiteObject(site);
390 		
391 		if ( ssoSite == null)
392 		{
393 			return false;	// no entry for site
394 		}
395 		
396 		// Get the principal from the subject
397 		BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
398 		String fullPath = principal.getFullPath();
399 		
400 				
401 		// Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
402 		Collection remoteForSite		= ssoSite.getRemotePrincipals();
403 		Collection principalsForSite	= ssoSite.getPrincipals();	// Users
404 		
405 		// If any of them don't exist just return
406 		if (principalsForSite == null || remoteForSite== null )
407 		    return false;	// no entry
408 		
409 		Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
410 		
411 		if ( remoteForPrincipals == null)
412 		    return false;	// no entry
413 		
414 		// Get remote Principal that matches the site and the principal
415 		if (findRemoteMatch(remoteForPrincipals, remoteForSite) == null )
416 		{
417 		    return false;	// No entry
418 		}
419 		else
420 		{
421 		    return true;	// Has an entry
422 		}
423 	}
424 
425 	/* (non-Javadoc)
426 	 * @see org.apache.jetspeed.sso.SSOProvider#getCredentials(javax.security.auth.Subject, java.lang.String)
427 	 */
428 	public SSOContext getCredentials(Subject subject, String site)
429 			throws SSOException {
430 		
431 		// Initialization
432 		SSOSite ssoSite = getSSOSiteObject(site);
433 		
434 		if ( ssoSite == null)
435 			throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);	// no entry for site
436 		
437 		// Get the principal from the subject
438 		BasePrincipal principal = (BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class);
439 		String fullPath = principal.getFullPath();
440 		
441 		// Filter the credentials for the given principals
442 		SSOContext context = getCredential(ssoSite, fullPath);	
443 		
444 		if ( context == null)
445 			throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);	// no entry for site
446 		
447 		return context;
448 	}
449 
450 	/* addCredential()
451 		 * Adds credentials for a user to the site. If the site doesn't exist it will be created
452 	 * @see org.apache.jetspeed.sso.SSOProvider#addCredentialsForSite(javax.security.auth.Subject, java.lang.String, java.lang.String)
453 	 */
454 	public void addCredentialsForSite(Subject subject, String remoteUser, String site, String pwd)
455 			throws SSOException {
456 		
457 		// Check if an entry for the site already exists otherwise create a new one
458 		SSOSite ssoSite = getSSOSiteObject(site);
459 		if (ssoSite == null)
460 		{
461 			// Create a new site
462 			ssoSite = new SSOSiteImpl();
463 			ssoSite.setSiteURL(site);
464 			ssoSite.setName(site);
465 			ssoSite.setCertificateRequired(false);
466 			ssoSite.setAllowUserSet(true);
467 			// By default we use ChallengeResponse Authentication
468 			ssoSite.setChallengeResponseAuthentication(true);
469 			ssoSite.setFormAuthentication(false);
470 			
471 			// Store the site so that we get a valid SSOSiteID
472 			try
473 	         {
474 	             getPersistenceBrokerTemplate().store(ssoSite);
475 	          }
476 	         catch (Exception e)
477 	         {
478 	         	e.printStackTrace();
479 	            throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
480 	         }
481 		}
482 		
483 		// Get the Principal information (logged in user)
484 		String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
485 		String principalName = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getName();
486 		
487 		// Add an entry for the principal to the site if it doesn't exist
488 		SSOPrincipal principal = this.getPrincipalForSite(ssoSite, fullPath);
489 		
490 		if (principal == null )
491 		{
492 		    principal = getSSOPrincipal(fullPath);
493 		    ssoSite.addPrincipal(principal);
494 		}
495 		else
496 		{
497 		    // Check if the entry the user likes to update exists already
498 		    Collection remoteForSite = ssoSite.getRemotePrincipals();
499 		    Collection principalsForSite = ssoSite.getPrincipals();
500 		    
501 		    if ( remoteForSite != null && principalsForSite != null)
502 		    {
503 		        Collection remoteForPrincipals = this.getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
504 		        if ( remoteForPrincipals != null)
505 		        {
506 			        if (findRemoteMatch(remoteForPrincipals, remoteForSite) != null )
507 			        {
508 			            // Entry exists can't to an add has to call update
509 			            throw new SSOException(SSOException.REMOTE_PRINCIPAL_EXISTS_CALL_UPDATE);
510 			        }
511 		        }
512 		    }
513 		}
514 		
515 		if (principal == null)
516 			throw new SSOException(SSOException.FAILED_ADDING_PRINCIPAL_TO_MAPPING_TABLE_FOR_SITE);
517 		
518 		// Create a remote principal and credentials
519 		InternalUserPrincipalImpl remotePrincipal = new InternalUserPrincipalImpl(remoteUser);
520 		
521 		/*
522 		 * The RemotePrincipal (class InternalUserPrincipal) will have a fullPath that identifies the entry as an SSO credential.
523 		 * The entry has to be unique for a site and principal  (GROUP -or- USER ) an therefore it needs to be encoded as following:
524 		 * The convention for the path is the following: /sso/SiteID/{user|group}/{user name | group name}/remote user name
525 		 */
526 		if ( fullPath.indexOf("/group/") > -1)
527 		    remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/group/"+  principalName + "/" + remoteUser);
528 		else
529 		    remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/user/"+ principalName + "/" + remoteUser);
530 		
531 		// New credential object for remote principal
532 		 InternalCredentialImpl credential = 
533             new InternalCredentialImpl(remotePrincipal.getPrincipalId(),
534             		this.scramble(pwd), 0, DefaultPasswordCredentialImpl.class.getName());
535 		 
536 		 if ( remotePrincipal.getCredentials() == null)
537 		 	remotePrincipal.setCredentials(new ArrayList(0));
538 		 
539 		remotePrincipal.getCredentials().add( credential);
540 		
541 		// Add it to Principals remotePrincipals list
542 		principal.addRemotePrincipal(remotePrincipal);
543 
544 		// Update the site remotePrincipals list
545 		ssoSite.getRemotePrincipals().add(remotePrincipal);
546 		
547 		 	
548 		// Update database and reset cache
549 		 try
550          {
551              getPersistenceBrokerTemplate().store(ssoSite);
552              
553              // Persist Principal/Remote
554      		getPersistenceBrokerTemplate().store(principal);
555           }
556          catch (Exception e)
557          {
558          	e.printStackTrace();
559             throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
560          }
561          
562          // Add to site
563          this.mapSite.put(site, ssoSite);
564 	}
565 
566 	/* (non-Javadoc)
567 	 * @see org.apache.jetspeed.sso.SSOProvider#removeCredentialsForSite(javax.security.auth.Subject, java.lang.String)
568 	 */
569 	public void removeCredentialsForSite(Subject subject, String site)
570 			throws SSOException {
571 		
572 		// Initailization
573 		InternalUserPrincipal remotePrincipal = null;
574 		//Get the site
575 		SSOSite ssoSite = getSSOSiteObject(site);
576 		if (ssoSite == null)
577 		{
578 			throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
579 		}
580 		
581 		// Get the Principal information
582 		String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
583 		
584 		try
585 		{
586 			//	Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
587 			Collection principalsForSite = ssoSite.getPrincipals();
588 			Collection remoteForSite = ssoSite.getRemotePrincipals();
589 			
590 			// If any of them don't exist just return
591 			if (principalsForSite == null || remoteForSite== null )
592 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
593 			
594 			Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
595 			
596 			if ( remoteForPrincipals == null)
597 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
598 			
599 			// Get remote Principal that matches the site and the principal
600 			if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
601 			{
602 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
603 			}
604 
605 			// Update assocation tables
606 			ssoSite.getRemotePrincipals().remove(remotePrincipal);
607 			
608 			if (remoteForPrincipals.remove(remotePrincipal) == true)
609 			
610 			// Update the site
611 			getPersistenceBrokerTemplate().store(ssoSite);
612 
613 			// delete the remote Principal from the SECURITY_PRINCIPAL table
614 		    getPersistenceBrokerTemplate().delete(remotePrincipal);
615 		    
616 						
617 		}
618 		catch(SSOException ssoex)
619 		{
620 			throw new SSOException(ssoex);
621 		}
622 		catch (Exception e)
623         {
624         	e.printStackTrace();
625             // current OJB model implementation isn't 100% correct, make sure no stale/broken state is left behind
626             mapSite.remove(site);
627            throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
628         }
629 								
630 		// Update database
631 		 try
632          {
633              getPersistenceBrokerTemplate().store(ssoSite);
634           }
635          catch (Exception e)
636          {
637          	e.printStackTrace();
638             throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
639          }
640          finally
641          {
642              // current OJB model implementation isn't 100% correct, make sure no stale/broken state is left behind
643              mapSite.remove(site);
644          }
645          
646 	}
647 	
648 	/***
649 	 * updateCredentialsForSite
650 	 * @param subject	Current subject
651 	 * @param remoteUser	remote user login
652 	 * @param site		URL or description of site
653 	 * @param pwd	Password for credentail
654 	 */
655 	public void  updateCredentialsForSite(Subject subject, String remoteUser, String site, String pwd)  
656 	    throws SSOException
657 	    {
658 	        // Check if the the current user has a credential for the site
659 		
660 			// Update the credential
661 			//		 Initailization
662 			InternalUserPrincipal remotePrincipal = null;
663 			
664 			//Get the site
665 			SSOSite ssoSite = getSSOSiteObject(site);
666 			if (ssoSite == null)
667 			{
668 				throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
669 			}
670 			
671 			// Get the Principal information
672 			String fullPath = ((BasePrincipal)SecurityHelper.getBestPrincipal(subject, UserPrincipal.class)).getFullPath();
673 			
674 			//	Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
675 			Collection principalsForSite	= ssoSite.getPrincipals();
676 			Collection remoteForSite		= ssoSite.getRemotePrincipals();
677 			
678 			// If any of them don't exist just return
679 			if (principalsForSite == null || remoteForSite== null )
680 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
681 			
682 			Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
683 			
684 			if ( remoteForPrincipals == null)
685 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
686 			
687 			// Get remote Principal that matches the site and the principal
688 			if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
689 			{
690 			    throw new SSOException(SSOException.NO_CREDENTIALS_FOR_SITE);
691 			}
692 						
693 			// Update principal information
694 			//remotePrincipal.setFullPath("/sso/" + ssoSite.getSiteId() + "/user/"+ principalName + "/" + remoteUser);
695 			
696 			InternalCredential credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
697 					
698 			// New credential object
699 			 if ( credential != null) 
700 				// Remove credential and principal from mapping
701 				 credential.setValue(this.scramble(pwd));
702 			
703 			// Update database and reset cache
704 			 try
705 			 {
706 			     getPersistenceBrokerTemplate().store(credential);
707 			  }
708 			 catch (Exception e)
709 			 {
710 			 	e.printStackTrace();
711 			    throw new SSOException(SSOException.FAILED_STORING_SITE_INFO_IN_DB + e.toString() );
712 			 }			 
713 	    }
714 	
715 	/*
716 	 * Helper utilities
717 	 * 
718 	 */
719 	
720 	/*
721 	 * getSSOSiteObject
722 	 * Obtains the Site information including the credentials for a site (url).
723 	 */
724 	
725 	private SSOSite getSSOSiteObject(String site)
726 	{
727 		//Initialization
728 		SSOSite ssoSite = null;
729 		
730 		//Check if the site is in the map
731 		if (mapSite.containsKey(site) == false )
732 		{
733 			//	Go to the database and fetch the information for this site
734 			//	Find the MediaType by matching the Mimetype
735 		            
736 		    Criteria filter = new Criteria();       
737 		    filter.addEqualTo("siteURL", site);
738 		    
739 		    QueryByCriteria query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
740 		    Collection ssoSiteCollection = getPersistenceBrokerTemplate().getCollectionByQuery(query);                    
741 		    
742 		    if ( ssoSiteCollection != null && ssoSiteCollection.isEmpty() != true)
743 		    {
744 		    	Iterator itSite = ssoSiteCollection.iterator();
745 		    	// Get the site from the collection. There should be only one entry (uniqueness)
746 		    	if (itSite.hasNext())
747 			    {
748 				    	ssoSite = (SSOSite) itSite.next();
749 			    }
750 		    	
751 		    	// Add it to the map
752 		    	mapSite.put(site, ssoSite);
753 		    }
754 		    else
755 		    {
756 		    	// No entry for this site
757 		    	return null;
758 		    }
759 		}
760 		else
761 		{
762 			ssoSite = (SSOSite)mapSite.get(site);
763 		}
764 		
765 		return ssoSite;
766 	}
767 	
768 	/*
769 	 * getCredential
770 	 * returns the credentials for a given user
771 	 */
772 	private SSOContext  getCredential(SSOSite ssoSite, String fullPath)
773 	{
774 		InternalCredential credential = null;
775 		InternalUserPrincipal remotePrincipal = null;
776 		//	Get remotePrincipals for Site and match them with the Remote Principal for the Principal attached to site
777 		Collection principalsForSite = ssoSite.getPrincipals();
778 		Collection remoteForSite = ssoSite.getRemotePrincipals();
779 		
780 		// If any of them don't exist just return
781 		if ( principalsForSite == null  || remoteForSite== null )
782 		    return null;	// no entry
783 		
784 		Collection remoteForPrincipals = getRemotePrincipalsForPrincipal(principalsForSite, fullPath);
785 				
786 		if ( remoteForPrincipals == null)
787 		    return null;	// no entry
788 		
789 		// Get remote Principal that matches the site and the principal
790 		if ((remotePrincipal = findRemoteMatch(remoteForPrincipals, remoteForSite)) == null )
791 		{
792 		    return null;	// No entry
793 		}
794 		else
795 		{
796 		    // Has an entry
797 			if ( remotePrincipal.getCredentials() != null)
798 				credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
799 			
800 			// Error checking  -- should have a credential at this point
801 			if ( credential == null)
802 			{
803 //				System.out.println("Warning: Remote User " + remotePrincipal.getFullPath() + " doesn't have a credential");
804 				return null; 
805 			}
806 		}
807 		
808 		//	Create new context
809 		String name = stripPrincipalName(remotePrincipal.getFullPath());
810 		
811 		SSOContext context = new SSOContextImpl(credential.getPrincipalId(), name, this.unscramble(credential.getValue()));
812 		
813 		return context;
814 	}
815 	
816     private String stripPrincipalName(String fullPath)
817     {
818         String name;
819         int ix = fullPath.lastIndexOf('/');
820         if ( ix != -1)
821             name = fullPath.substring(ix + 1);
822         else
823             name = new String(fullPath);
824         
825         return name;        
826     }
827 
828 	/*
829 	 * Get a Collection of remote Principals for the logged in principal identified by the full path
830 	 *    
831 	private Collection getRemotePrincipalsForPrincipal(SSOSite ssoSite, String fullPath)
832 	{
833 		// The site orincipals list contains a list of remote principals for the user
834 		Collection principals = ssoSite.getPrincipals();
835 		
836 		if ( principals == null )
837 			return null;	// No principals for this site
838 		
839 		Iterator ixPrincipals = principals.iterator();
840 		while (ixPrincipals.hasNext())
841 		{
842 			SSOPrincipal principal = (SSOPrincipal)ixPrincipals.next();
843 			if (         principal != null 
844 			        && principal.getFullPath().compareToIgnoreCase(fullPath) == 0 )
845 			{
846 				// Found Principal -- extract remote principals 
847 				return principal.getRemotePrincipals();
848 			}
849 		}
850 		
851 		// Principal is not in list
852 		return null;
853 	}
854     */
855 	
856 	/*
857 	 * getPrincipalForSite()
858 	 * returns a principal that matches the full path for the site or creates a new entry if it doesn't exist
859 	 */
860 	private SSOPrincipal getPrincipalForSite(SSOSite ssoSite, String fullPath)
861 	{
862 		SSOPrincipal principal = null;
863 		Collection principalsForSite = ssoSite.getPrincipals();
864 		
865 		if ( principalsForSite != null)
866 		{
867 			Iterator itPrincipals = principalsForSite.iterator();
868 			while (itPrincipals.hasNext() && principal == null)
869 			{
870 				SSOPrincipal tmp  = (SSOPrincipal)itPrincipals.next();
871 				if ( 		 tmp != null 
872 				       && tmp.getFullPath().compareToIgnoreCase(fullPath) == 0 )
873 					principal = tmp;	// Found existing entry
874 			}
875 		}
876 		
877 		return principal;
878 	}
879 	
880 	private SSOPrincipal getSSOPrincipal(String fullPath)
881 	{
882 	    // FInd if the principal exists in the SECURITY_PRINCIPAL table
883 	    SSOPrincipal principal = null;
884 	    
885 		Criteria filter = new Criteria();       
886 	    filter.addEqualTo("fullPath", fullPath);
887 	    
888 	    QueryByCriteria query = QueryFactory.newQuery(SSOPrincipalImpl.class, filter);
889 	    Collection principals = getPersistenceBrokerTemplate().getCollectionByQuery(query);                    
890 	    
891 	    if ( principals != null && principals.isEmpty() != true)
892 	    {
893 	    	Iterator itPrincipals = principals.iterator();
894 	    	// Get the site from the collection. There should be only one entry (uniqueness)
895 	    	if (itPrincipals.hasNext())
896 		    {
897 	    		principal = (SSOPrincipal) itPrincipals.next();
898 		    }
899 	    }
900 	    
901 		return principal;		
902 	}
903 	
904 	
905 	
906 	/***
907 	 * removeRemotePrincipalForPrincipal
908 	 * @param site
909 	 * @param fullPath
910 	 * @return
911 	 * 
912 	 * removes remotePrincipal for a site & principal
913 	 *
914 	private InternalUserPrincipal  removeRemotePrincipalForPrincipal(SSOSite site, String fullPath) throws SSOException
915 	{
916 		if (site.getPrincipals() != null)
917 		{
918 			Iterator itPrincipals = site.getPrincipals().iterator();
919 			while (itPrincipals.hasNext())
920 			{
921 				SSOPrincipal tmp = (SSOPrincipal)itPrincipals.next();
922 				if (tmp.getFullPath().compareToIgnoreCase(fullPath) == 0)
923 				{
924 					// Found -- get the remotePrincipal
925 					Collection collRemotePrincipals = tmp.getRemotePrincipals() ;
926 					if (collRemotePrincipals != null)
927 					{
928 					
929 						Iterator itRemotePrincipals = collRemotePrincipals.iterator();
930 						if  (itRemotePrincipals.hasNext())
931 						{
932 							InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)itRemotePrincipals.next();
933 							// Found remove the object
934 							collRemotePrincipals.remove(remotePrincipal);
935 							return remotePrincipal;
936 						}
937 					}
938 				}
939 			}
940 		}		
941 		
942 		throw new SSOException(SSOException.REQUESTED_PRINCIPAL_DOES_NOT_EXIST);
943 	}
944 	*/
945     
946 	/*
947 	 * 
948 	 * 
949 	 */
950 	private InternalUserPrincipal findRemoteMatch(Collection remoteForPrincipals, Collection remoteForSite)
951 	{
952 	    // Iterate over the lists and find match
953 	    Iterator itRemoteForPrincipals = remoteForPrincipals.iterator();
954 	    while ( itRemoteForPrincipals.hasNext())
955 	    {
956 	        InternalUserPrincipal remoteForPrincipal = (InternalUserPrincipal)itRemoteForPrincipals.next();
957 	        
958 	        // Find a match in the site list
959 	        Iterator itRemoteForSite = remoteForSite.iterator();
960 		    while ( itRemoteForSite.hasNext())
961 		    {
962 		        InternalUserPrincipal tmp = (InternalUserPrincipal)itRemoteForSite.next();
963 		        
964 		        if ( tmp.getPrincipalId() == remoteForPrincipal.getPrincipalId() )
965 		            return remoteForPrincipal;
966 		    }
967 	    }
968 	    // No match found
969 	    return null;
970 	}
971 	
972 	/*
973 	 * getRemotePrincipalsForPrincipals
974 	 * Checks if the user has any remote principals. If the principal is a group expand the group and
975 	 * check if the requesting user is a part of the group.
976 	 */
977 	private Collection getRemotePrincipalsForPrincipal(Collection principalsForSite, String fullPath)
978 	{
979 	    if (principalsForSite != null )
980 	    {
981 		    Iterator itPrincipalsForSite = principalsForSite.iterator();
982 		    while (itPrincipalsForSite.hasNext())
983 		    {
984 		        String principalFullPath = null;
985 		        SSOPrincipal principal = (SSOPrincipal)itPrincipalsForSite.next();
986 		        principalFullPath = principal.getFullPath();
987 		        
988 		        /* If the Principal is for a Group expand the Group and check if the user identified
989 		        * by the fullPath is a member of the Group. If the user is a member of the Group
990 		        * return the remote Credentials for the current Principal.
991 		        */
992 		        if ( principalFullPath.indexOf("/group/") == -1)
993 		        {
994 		            // USER
995 		            if ( principalFullPath.compareToIgnoreCase(fullPath) == 0)
996 		                return principal.getRemotePrincipals();
997 		        }
998 		        else
999 		        {
1000 		            /* GROUP 
1001 		             * If the full path is for a group (delete/add) just return the the list of remotePrincipals
1002 		             * For a lookup (hasCredentials) the user needs to be mapped against each member of the group
1003 		            */
1004 		            if ( principalFullPath.compareToIgnoreCase(fullPath) == 0)
1005 		                return principal.getRemotePrincipals();
1006 		            
1007 		            /* Expand the Group and find a match */
1008 			        InternalGroupPrincipal  groupPrincipal = getGroupPrincipals(principalFullPath);
1009 			        
1010 			        // Found Group that matches the name
1011 			        if (groupPrincipal != null)
1012 		            {
1013 			            Collection usersInGroup = groupPrincipal.getUserPrincipals();
1014 			            Iterator itUsers = usersInGroup.iterator();
1015 		                while (itUsers.hasNext())
1016 		                {
1017 		                    InternalUserPrincipal user = (InternalUserPrincipal)itUsers.next();
1018 		                    if (user.getFullPath().compareToIgnoreCase(fullPath) == 0)
1019 		                    {
1020 		                        // User is member of the group
1021 		                        return principal.getRemotePrincipals();
1022 		                    }
1023 		                }
1024 		            }
1025 		        }  
1026 		    }
1027 	    }
1028 	    
1029 	    // No match found
1030 	    return null;
1031 	}
1032     
1033     public SSOSite getSite(String siteUrl)
1034     {
1035         Criteria filter = new Criteria();
1036         filter.addEqualTo("url", siteUrl);
1037         Query query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
1038         SSOSite site = (SSOSite) getPersistenceBrokerTemplate().getObjectByQuery(query);
1039         return site;       
1040     }
1041     
1042     public void updateSite(SSOSite site)
1043     throws SSOException
1044     {
1045         try
1046         {
1047             getPersistenceBrokerTemplate().store(site);
1048             this.mapSite.put(site.getName(), site);                        
1049         }
1050         catch (Exception e)
1051         {
1052             String msg = "Unable to remove SSO Site: " + site.getName();
1053             logger.error(msg, e);
1054             throw new SSOException(msg, e);
1055         }        
1056     }
1057     
1058     /***
1059      * Add a new site that uses Form Authentication
1060      * @param siteName
1061      * @param siteUrl
1062      * @param realm
1063      * @param userField
1064      * @param pwdField
1065      * @throws SSOException
1066      */
1067     public void addSiteFormAuthenticated(String siteName, String siteUrl, String realm, String userField, String pwdField)
1068     throws SSOException
1069     {
1070     	try
1071         {
1072             SSOSite ssoSite = new SSOSiteImpl();
1073             ssoSite.setSiteURL(siteUrl);
1074             ssoSite.setName(siteName);
1075             ssoSite.setCertificateRequired(false);
1076             ssoSite.setAllowUserSet(true);
1077             ssoSite.setRealm(realm);
1078             ssoSite.setFormAuthentication(true);
1079             ssoSite.setFormUserField(userField);
1080             ssoSite.setFormPwdField(pwdField);
1081             getPersistenceBrokerTemplate().store(ssoSite);
1082             this.mapSite.put(siteName, ssoSite);            
1083         }
1084         catch (Exception e)
1085         {
1086             String msg = "Unable to add SSO Site: " + siteName;
1087             logger.error(msg, e);
1088             throw new SSOException(msg, e);
1089         }  
1090     }
1091     
1092     /***
1093      * Add a new site that uses ChallengeResponse Authentication
1094      * @param siteName
1095      * @param siteUrl
1096      * @param realm
1097      * @throws SSOException
1098      */
1099     public void addSiteChallengeResponse(String siteName, String siteUrl, String realm)
1100     throws SSOException
1101     {
1102     	try
1103         {
1104             SSOSite ssoSite = new SSOSiteImpl();
1105             ssoSite.setSiteURL(siteUrl);
1106             ssoSite.setName(siteName);
1107             ssoSite.setCertificateRequired(false);
1108             ssoSite.setAllowUserSet(true);
1109             ssoSite.setRealm(realm);
1110             ssoSite.setChallengeResponseAuthentication(true);
1111              getPersistenceBrokerTemplate().store(ssoSite);
1112             this.mapSite.put(siteName, ssoSite);            
1113         }
1114         catch (Exception e)
1115         {
1116             String msg = "Unable to add SSO Site: " + siteName;
1117             logger.error(msg, e);
1118             throw new SSOException(msg, e);
1119         }  
1120     }
1121     
1122     public void addSite(String siteName, String siteUrl)
1123     throws SSOException
1124     {
1125         try
1126         {
1127             SSOSite ssoSite = new SSOSiteImpl();
1128             ssoSite.setSiteURL(siteUrl);
1129             ssoSite.setName(siteName);
1130             ssoSite.setCertificateRequired(false);
1131             ssoSite.setAllowUserSet(true);            
1132             getPersistenceBrokerTemplate().store(ssoSite);
1133             this.mapSite.put(siteName, ssoSite);            
1134         }
1135         catch (Exception e)
1136         {
1137             String msg = "Unable to remove SSO Site: " + siteName;
1138             logger.error(msg, e);
1139             throw new SSOException(msg, e);
1140         }                
1141     }
1142     
1143     public void removeSite(SSOSite site)
1144     throws SSOException
1145     {
1146         try
1147         {
1148             getPersistenceBrokerTemplate().delete(site);
1149             this.mapSite.remove(site);
1150 
1151         }
1152         catch (Exception e)
1153         {
1154             String msg = "Unable to remove SSO Site: " + site.getName();
1155             logger.error(msg, e);
1156             throw new SSOException(msg, e);
1157         }        
1158     }
1159         
1160     public List getPrincipalsForSite(SSOSite site)
1161     {
1162         List list = new ArrayList();
1163         Iterator principals = site.getRemotePrincipals().iterator();
1164         while (principals.hasNext())
1165         {
1166             InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)principals.next();
1167             Iterator creds = remotePrincipal.getCredentials().iterator();
1168             while (creds.hasNext())
1169             {
1170                 InternalCredential cred = (InternalCredential) creds.next();
1171                 SSOContext context = new SSOContextImpl(remotePrincipal.getPrincipalId(), 
1172                                                 stripPrincipalName(remotePrincipal.getFullPath()), 
1173                                                 cred.getValue(), 
1174                                                 stripPortalPrincipalName(remotePrincipal.getFullPath()));
1175                 list.add(context);
1176             }
1177         }
1178         return list;
1179     }
1180 
1181     
1182     private String stripPortalPrincipalName(String fullPath)
1183     {
1184         StringTokenizer tokenizer = new StringTokenizer(fullPath, "/");
1185         while (tokenizer.hasMoreTokens())
1186         {
1187             String token = tokenizer.nextToken();
1188             if (token.equals("user") || token.equals("group"))
1189             {
1190                  if (tokenizer.hasMoreTokens())
1191                 {
1192                     return tokenizer.nextToken();
1193                 }
1194             }
1195         }
1196         return fullPath;        
1197     }
1198     
1199     private InternalGroupPrincipal  getGroupPrincipals(String principalFullPath)
1200     {
1201         // Get to the backend to return the group that matches the full path
1202         Criteria filter = new Criteria();
1203         filter.addEqualTo("fullPath", principalFullPath);
1204         Query query = QueryFactory.newQuery(InternalGroupPrincipalImpl.class, filter);
1205         InternalGroupPrincipal group = (InternalGroupPrincipal) getPersistenceBrokerTemplate().getObjectByQuery(query);
1206         return group;       
1207     }
1208     
1209     /*
1210     private SSOSite getSiteForRemoteUser(String fullPath)
1211     {
1212     	// Get Site for remote user
1213         Criteria filter = new Criteria();
1214         filter.addEqualTo("remotePrincipals.fullPath", fullPath);
1215         Query query = QueryFactory.newQuery(SSOSiteImpl.class, filter);
1216         return  (SSOSite) getPersistenceBrokerTemplate().getObjectByQuery(query);
1217     }
1218     */
1219     
1220     private String getContentFromURL(String proxyID, String destUrl, SSOSite[] sites, boolean bRefresh ) throws SSOException
1221     {
1222     	URL urlObj = null;
1223     	
1224     	// Result Buffer
1225     	//BufferedInputStream bis = null;
1226     	String resultPage;
1227     	
1228     	String strErrorMessage = "SSO Component Error. Failed to get content for URL " + destUrl;
1229     	
1230     	try
1231     	{
1232     		urlObj = new URL(destUrl);
1233     	}
1234     	catch (MalformedURLException e)
1235     	{
1236     		String msg = ("Error -- Malformed URL [" + destUrl +"] for SSO authenticated destination");
1237     		log.error(msg);
1238     		throw new SSOException(msg, e);
1239     	}
1240     	
1241     	/* 
1242     	 * Setup HTTPClient
1243     	 * Check if an HTTP Client already exists for the given /user/site
1244     	 */
1245     	HttpClient client = (HttpClient)this.clientProxy.get(proxyID);
1246     	GetMethod get = null;
1247     	
1248     	if (bRefresh == true || client == null)
1249     	{
1250     		if (log.isInfoEnabled())
1251     			log.info("SSO Component -- Create new HTTP Client object for Principal/URL [" + proxyID+ "]");
1252     		
1253 	    	client = new HttpClient();
1254 	    	client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
1255 	    	
1256 	    	int numberOfSites = sites.length;
1257 	    	
1258 	    	// Do all the logins for the site
1259 	    	for (int i=0; i<numberOfSites; i++)
1260 	    	{
1261 	    		SSOSite site = sites[i];
1262 	    		
1263 	    		if (site != null)
1264 	    		{
1265 	    			Iterator itRemotePrincipals = site.getRemotePrincipals().iterator();
1266 	    			while (itRemotePrincipals.hasNext() )
1267 	    			{
1268 	    				InternalUserPrincipal remotePrincipal = (InternalUserPrincipal)itRemotePrincipals.next();
1269 	            		if (remotePrincipal != null)
1270 	            		{
1271 	            			InternalCredential credential = null;
1272 	            			if ( remotePrincipal.getCredentials() != null)
1273 	            				credential = (InternalCredential)remotePrincipal.getCredentials().iterator().next();
1274 	            			
1275 	            			if (credential != null)
1276 	            			{
1277 	            				if (log.isInfoEnabled())
1278 	            					log.info("SSOComponent -- Remote Principal ["+stripPrincipalName(remotePrincipal.getFullPath())+"] has credential ["+this.unscramble(credential.getValue())+ "]");
1279 	            				
1280 	            				client.getState().setCredentials(
1281 	            		    			site.getRealm(),
1282 	            		                urlObj.getHost(),
1283 	            		                new UsernamePasswordCredentials(stripPrincipalName(remotePrincipal.getFullPath()),  this.unscramble(credential.getValue()))
1284 	            		            );
1285 	            				
1286 	            				// Build URL if it's Form authentication
1287 	            				StringBuffer siteURL = new StringBuffer(site.getSiteURL());
1288 		       					
1289 		        				// Check if it's form based or ChallengeResponse
1290 	        					if (site.isFormAuthentication())
1291 	        					{
1292 	        						siteURL.append("?").append(site.getFormUserField()).append("=").append(stripPrincipalName(remotePrincipal.getFullPath())).append("&").append(site.getFormPwdField()).append("=").append(this.unscramble(credential.getValue()));
1293 	        					}
1294 	            				
1295 	            				get = new GetMethod(siteURL.toString());
1296 	
1297 	            	            // Tell the GET method to automatically handle authentication. The
1298 	            	            // method will use any appropriate credentials to handle basic
1299 	            	            // authentication requests.  Setting this value to false will cause
1300 	            	            // any request for authentication to return with a status of 401.
1301 	            	            // It will then be up to the client to handle the authentication.
1302 	            	            get.setDoAuthentication( true );
1303 	            	            try {
1304 	            	                // execute the GET
1305 	            	                int status = client.executeMethod( get );
1306 	            	                
1307 	            	                if (log.isInfoEnabled() )
1308 	            	                		log.info("Accessing site [" + site.getSiteURL() + "]. HTTP Status [" +status+ "]" );
1309 	            	                
1310 	            	                /*
1311 	            	    	    	 * If the destination URL and the SSO url match
1312 	            	    	    	 * use the authentication process but return immediately
1313 	            	    	    	 * the result page.
1314 	            	    	    	 */
1315 	            	                if( destUrl.compareTo(site.getSiteURL()) == 0 && numberOfSites == 1)
1316 	            	                {
1317 	            	                	if (log.isInfoEnabled() )
1318 	            	                		log.info("SSO Component --SSO Site and destination URL match. Go and get the content." );
1319 	            	                	
1320 	            	                	//try
1321 	            	            		//{
1322 	            	            			//bis = new BufferedInputStream(get.getResponseBodyAsStream());
1323 	            	            			resultPage = get.getResponseBodyAsString();
1324 	            	            		//}
1325 	            	            		//catch(IOException ioe)
1326 	            	            		//{
1327 	            	            		//	log.error(strErrorMessage, ioe);
1328 	            	            		//	throw new SSOException (strErrorMessage, ioe);	
1329 	            	            		//}
1330 
1331 	            	            		get.releaseConnection();
1332 	            	            		
1333 	            	            		//	Add the client object to the cache
1334 	            	        	    	this.clientProxy.put(proxyID, client);
1335 	            	            		
1336 	            	            		//return bis;
1337 	            	        	    	return resultPage;
1338 	            	                }
1339 	            	        
1340 		            			} catch (Exception e) {
1341 		                        	log.error("Exception while authentication. Error: " +e);	                        
1342 		                        }
1343 		            			
1344 		            			get.releaseConnection();
1345 	             			}
1346 	            		}
1347 	    			}
1348 	    		}   		
1349 	    	}
1350 	    	
1351 	    	// Add the client object to the cache
1352 	    	this.clientProxy.put(proxyID, client);
1353     	}
1354     	else
1355     	{
1356     		if (log.isInfoEnabled())
1357     			log.info("SSO Component -- Use cached HTTP Client object for Principal/URL [" + proxyID+ "]");
1358     	}
1359     	
1360     	// All the SSO authentication done go to the destination url
1361 		get = new GetMethod(destUrl);
1362 		try {
1363             // execute the GET
1364             int status = client.executeMethod( get );
1365             
1366             log.info("Accessing site [" + destUrl + "]. HTTP Status [" +status+ "]" );
1367     
1368 		} catch (Exception e) {
1369         	log.error("Exception while authentication. Error: " +e);	                        
1370         }
1371 		
1372 		
1373 		try
1374 		{
1375 			//bis = new BufferedInputStream(get.getResponseBodyAsStream());
1376 			resultPage = get.getResponseBodyAsString();
1377 		}
1378 		catch(IOException ioe)
1379 		{
1380 			log.error(strErrorMessage, ioe);
1381 			throw new SSOException (strErrorMessage, ioe);
1382         }
1383 		catch (Exception e)
1384 		{
1385 			log.error(strErrorMessage, e);
1386 			throw new SSOException (strErrorMessage, e);
1387 			
1388 		}
1389         finally
1390         {
1391             get.releaseConnection();
1392         }
1393 		
1394 		//return bis;
1395 		return resultPage;
1396     }
1397     
1398     /*
1399      * Simple encryption decryption routines since the API creates credentials 
1400      * together with an user.
1401      * TODO: re-implement when Security API is more flexible
1402      */
1403     static char[] scrambler ="Jestspeed-2 is getting ready for release".toCharArray();
1404     
1405     private String scramble(String pwd)
1406     {
1407         // xor-ing persistent String values is dangerous because of the (uncommon) way Java encodes UTF-8 0x00 (and some other characters).
1408         // See: http://en.wikipedia.org/wiki/UTF-8#Java
1409         // On some database platforms, like PostgreSQL this can lead to something like:
1410         //   org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
1411         // To prevent this, the resulting xored password is encoded in Base64
1412     	String xored = new String(xor(pwd.toCharArray(), scrambler));
1413         byte[] bytes = Base64.encodeBase64(xored.getBytes());
1414         String scrambled = new String(bytes);
1415         return scrambled;
1416     }
1417     
1418     private String unscramble(String pwd)
1419     {
1420     	byte[] bytes = pwd.getBytes();
1421         bytes = Base64.decodeBase64(bytes);
1422         String chars = new String(bytes);
1423         String unscrambled = new String(xor(chars.toCharArray(), scrambler));
1424         return unscrambled;
1425     }
1426     
1427     private char[] xor(char[] a, char[]b)
1428     {
1429     	int len = Math.min(a.length, b.length);
1430     	char[] result = new char[len];
1431     	for(int i=0; i<len;i++)
1432     	{
1433     		result[i] = (char) (a[i] ^ b[i]);
1434     	}
1435     	return result;
1436     }
1437 }