001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2007 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: TrustAuthorityClient.java,v 1.29 2009/10/13 23:19:48 mallas Exp $
026 *
027 */
028
029package com.sun.identity.wss.sts;
030
031import org.w3c.dom.Element;
032import org.w3c.dom.Node;
033
034import java.io.InputStream;
035import java.util.List;
036import java.util.Map;
037import java.util.HashMap;
038import java.util.List;
039import java.util.Set;
040import java.util.Iterator;
041import java.util.ArrayList;
042import java.util.logging.Level;
043import java.lang.reflect.Method;
044import java.lang.reflect.Constructor;
045import javax.servlet.ServletContext;
046import javax.xml.soap.SOAPMessage;
047import javax.xml.soap.SOAPException;
048import javax.security.auth.Subject;
049import javax.xml.namespace.QName;
050import javax.crypto.spec.SecretKeySpec;
051import java.security.Key;
052
053import com.sun.identity.shared.xml.XMLUtils;
054import com.sun.identity.shared.debug.Debug;
055import com.sun.identity.wss.security.SecurityToken;
056import com.sun.identity.wss.provider.ProviderConfig;
057import com.sun.identity.wss.provider.TrustAuthorityConfig;
058import com.sun.identity.wss.provider.STSConfig;
059import com.sun.identity.wss.security.AssertionToken;
060import com.sun.identity.wss.security.FAMSecurityToken;
061import com.sun.identity.wss.security.SAML2Token;
062import com.sun.identity.wss.security.UserNameToken;
063import com.sun.identity.wss.logging.LogUtil;
064import com.sun.identity.classloader.FAMClassLoader;
065import com.sun.identity.wss.security.SecurityMechanism;
066import com.sun.identity.wss.trust.WSTrustFactory;
067import com.sun.identity.wss.trust.WSTException;
068import com.sun.identity.wss.trust.RequestSecurityToken;
069import com.sun.identity.wss.trust.RequestSecurityTokenResponse;
070import com.sun.identity.wss.trust.RequestSecurityTokenResponseCollection;
071import com.sun.identity.common.SystemConfigurationUtil;
072import com.sun.identity.shared.jaxrpc.SOAPClient;
073import com.sun.identity.wss.security.handler.SOAPRequestHandler;
074import com.sun.identity.wss.security.SecurityException;
075import com.sun.identity.wss.trust.RequestedProofToken;
076import com.sun.identity.wss.trust.BinarySecret;
077import com.sun.identity.wss.trust.ClaimType;
078
079/**
080 * The class <code>TrustAuthorityClient</code> is a client API class that is 
081 * used to obtain the Security Tokens from the trusted authority services such 
082 * as Security Token Service (STS) or Liberty Discovery Service.
083 * 
084 * In this current OpenSSO 8.0 release, this client API is used as STS client 
085 * API class that retrieves Security Tokens from STS service by making WS-Trust 
086 * request and receiving WS-Trust response. 
087 * 
088 * @supported.all.api
089 */
090public class TrustAuthorityClient {
091    
092    private static Debug debug = STSUtils.debug;
093    private static Class clientTokenClass;
094    private static final String KEYTYPE = "KeyType";
095    private byte[] secretKey;
096    
097    /** 
098     * Creates a new instance of TrustAuthorityClient.
099     */
100    public TrustAuthorityClient() {
101    }
102    
103    /**
104     * Returns the <code>SecurityToken</code> for the web services client from
105     * a trusted authority, which is Security Token Service (STS). 
106     * The web services client configuation and web service
107     * information is identified by the client provider configuration.
108     *
109     * @param pc Provider configuration of the web services client.
110     * @param credential User's credential. The user's credential could be
111     *        Single Sign-On Token or a SAML Assertion or any other object.
112     * @return SecurityToken security token for the web services consumer.   
113     * @exception FAMSTSException if it's unable to retrieve security token.
114     */
115    public SecurityToken getSecurityToken(
116            ProviderConfig pc,            
117            Object credential) throws FAMSTSException {
118        return getSecurityToken(pc,null,null,null,credential,null,null, null);
119    }
120    
121    /**
122     * Returns the <code>SecurityToken</code> for the web services client from
123     * a trusted authority, which is Security Token Service (STS). 
124     * The web services client configuation and web service
125     * information is identified by the client provider configuration.
126     *
127     * @param pc Provider configuration of the web services client.
128     * @param credential User's credential. The user's credential could be
129     *        Single Sign-On Token or a SAML Assertion or any other object.
130     * @param context Web context under which this class is running.
131     * @return SecurityToken security token for the web services consumer.   
132     * @exception FAMSTSException if it's unable to retrieve security token.
133     */
134    public SecurityToken getSecurityToken(
135            ProviderConfig pc,            
136            Object credential,
137            ServletContext context) throws FAMSTSException {
138        return getSecurityToken(pc,null,null,null,credential,null,null,context);
139    }
140    
141    /**
142     * Returns the <code>SecurityToken</code> for the web services client from
143     * a trusted authority, which is Security Token Service (STS). 
144     *
145     * @param wspEndPoint Web Service Provider end point.
146     * @param stsEndPoint Security Token Service end point.
147     * @param stsMexEndPoint Security Token Service MEX end point.
148     * @param credential User's credential. The user's credential could be
149     *        Single Sign-On Token or a SAML Assertion or any other object.
150     * @param securityMech Required Security Mechanism by Web Service Client.
151     * @param context web context under which this class is running.
152     * @return SecurityToken security token for the web services consumer.   
153     * @exception FAMSTSException if it's unable to retrieve security token.
154     */
155    public SecurityToken getSecurityToken(
156            String wspEndPoint,
157            String stsEndPoint,
158            String stsMexEndPoint,
159            Object credential,
160            String securityMech,
161            ServletContext context) throws FAMSTSException {
162        return getSecurityToken(null,wspEndPoint,stsEndPoint,stsMexEndPoint,
163                credential,securityMech,null,context);
164    }
165    /**
166     * Returns the <code>SecurityToken</code> for the web services client from
167     * a trusted authority, which is Security Token Service (STS). 
168     *
169     * @param wspEndPoint Web Service Provider end point.
170     * @param stsEndPoint Security Token Service end point.
171     * @param stsMexEndPoint Security Token Service MEX end point.
172     * @param credential User's credential. The user's credential could be
173     *        Single Sign-On Token or a SAML Assertion or any other object.
174     * @param securityMech Required Security Mechanism by Web Service Client.
175     * @param tokenType the token type for the returned security token.
176     * @param context web context under which this class is running.
177     * @return SecurityToken security token for the web services consumer.   
178     * @exception FAMSTSException if it's unable to retrieve security token.
179     */
180    public SecurityToken getSecurityToken(
181            String wspEndPoint,
182            String stsEndPoint,
183            String stsMexEndPoint,
184            Object credential,
185            String securityMech,
186            String tokenType,
187            ServletContext context) throws FAMSTSException {
188        return getSecurityToken(null,wspEndPoint,stsEndPoint,stsMexEndPoint,
189                credential,securityMech,tokenType,context);
190    }  
191
192    // Gets Security Token from Security Token Service.
193    private SecurityToken getSecurityToken(
194            ProviderConfig pc,
195            String wspEndPoint,
196            String stsEndPoint,
197            String stsMexEndPoint,
198            Object credential,
199            String securityMech,
200            String tokenType,
201            ServletContext context) throws FAMSTSException {
202        
203        String keyTypeURI = STSConstants.WST13_PUBLIC_KEY;        
204        String stsAgentName = null;
205        String wstVersion = STSConstants.WST_VERSION_13;
206        List claims = null;
207        if (pc != null) {
208            List securityMechanisms = pc.getSecurityMechanisms();
209            if(securityMechanisms == null || securityMechanisms.isEmpty()) {
210               if(debug.messageEnabled()) {
211                  debug.message("TrustAuthorityClient.getSecurityToken::"+
212                          "Security Mechanisms are not configured");
213               }
214               return null;
215            }
216            securityMech = (String)securityMechanisms.get(0);
217            
218            STSConfig stsConfig = null;
219            TrustAuthorityConfig taconfig = pc.getTrustAuthorityConfig();
220            if(taconfig instanceof STSConfig) {
221               stsConfig = (STSConfig)taconfig;
222            } else {
223               throw new FAMSTSException(
224                       STSUtils.bundle.getString("invalidtaconfig"));
225            }
226            stsAgentName = stsConfig.getName();
227            stsEndPoint = stsConfig.getEndpoint();        
228            stsMexEndPoint = stsConfig.getMexEndpoint();
229            String keyType = stsConfig.getKeyType();
230             if(keyType.equals(STSConstants.SYMMETRIC_KEY)) {
231                keyTypeURI = STSConstants.WST13_SYMMETRIC_KEY; 
232            }
233            wstVersion = stsConfig.getProtocolVersion();
234            if(STSConstants.WST_VERSION_10.equals(wstVersion)) {
235               if(keyType.equals(STSConstants.SYMMETRIC_KEY)) {
236                  keyTypeURI = STSConstants.WST10_SYMMETRIC_KEY;
237               } else {
238                  keyTypeURI = STSConstants.WST10_PUBLIC_KEY;
239               }
240            }
241            String stsSecMech = (String)stsConfig.getSecurityMech().get(0);
242            if(stsSecMech.equals(
243                    SecurityMechanism.WSS_NULL_KERBEROS_TOKEN_URI) ||
244                stsSecMech.equals(
245                    SecurityMechanism.WSS_NULL_USERNAME_TOKEN_PLAIN_URI) ||
246                stsSecMech.equals(
247                    SecurityMechanism.WSS_NULL_USERNAME_TOKEN_URI) ||
248                stsSecMech.equals(
249                    SecurityMechanism.WSS_NULL_SAML2_SV_URI) ||
250                stsSecMech.equals(
251                    SecurityMechanism.WSS_NULL_SAML_SV_URI) ||    
252                stsSecMech.equals(SecurityMechanism.STS_SECURITY_URI)) {               
253                if(STSConstants.WST_VERSION_10.equals(wstVersion)) {
254                   keyTypeURI = STSConstants.WST10_BEARER_KEY;
255                } else {
256                   keyTypeURI = STSConstants.WST13_BEARER_KEY;
257                }
258            }
259            List requestedClaims = stsConfig.getRequestedClaims();
260            if(requestedClaims != null && !requestedClaims.isEmpty()) {
261               claims = getClaims(requestedClaims);
262            }
263            
264            wspEndPoint = pc.getWSPEndpoint();
265        } else {
266            Map attrMap = STSUtils.getAgentAttributes(stsEndPoint, 
267                "STSEndpoint", null, TrustAuthorityConfig.STS_TRUST_AUTHORITY);
268            stsAgentName = (String)attrMap.get("Name");
269            Set versionSet = (Set)attrMap.get(STSConstants.WST_VERSION_ATTR);
270            wstVersion = (String)versionSet.iterator().next();
271            if((wstVersion == null) || wstVersion.length() == 0)  {
272                wstVersion = STSConstants.WST_VERSION_13;
273            }
274                        
275            Set keySet = (Set)attrMap.get(KEYTYPE);
276            String keyType = STSConstants.PUBLIC_KEY;
277            
278            if(keySet != null) {
279               keyType = (String)keySet.iterator().next(); 
280            }
281            
282            if(keyType.equals(STSConstants.SYMMETRIC_KEY)) {
283               keyTypeURI = STSConstants.WST13_SYMMETRIC_KEY; 
284            }
285            if(STSConstants.WST_VERSION_10.equals(wstVersion)) {
286               if(keyType.equals(STSConstants.SYMMETRIC_KEY)) {
287                  keyTypeURI = STSConstants.WST10_SYMMETRIC_KEY;
288               } else {
289                  keyTypeURI = STSConstants.WST10_PUBLIC_KEY; 
290               }
291            }
292            Set values = (Set)attrMap.get("SecurityMech");
293            if (values != null && !values.isEmpty()) {
294                String stsSecMechTemp = (String)values.iterator().next();
295                if(stsSecMechTemp.equals(
296                    SecurityMechanism.WSS_NULL_KERBEROS_TOKEN_URI) ||
297                    stsSecMechTemp.equals(
298                    SecurityMechanism.WSS_NULL_USERNAME_TOKEN_PLAIN_URI) ||
299                    stsSecMechTemp.equals(
300                    SecurityMechanism.WSS_NULL_USERNAME_TOKEN_URI) ||
301                    stsSecMechTemp.equals(
302                    SecurityMechanism.WSS_NULL_SAML2_SV_URI) ||
303                    stsSecMechTemp.equals(
304                    SecurityMechanism.WSS_NULL_SAML_SV_URI) ||
305                    stsSecMechTemp.equals(SecurityMechanism.STS_SECURITY_URI)) {
306                    if(wstVersion.equals(STSConstants.WST_VERSION_10)) {
307                       keyTypeURI = STSConstants.WST10_BEARER_KEY;
308                    } else {
309                       keyTypeURI = STSConstants.WST13_BEARER_KEY;
310                    }
311                }
312            }
313            
314            Set requestedClaims = (Set)attrMap.get("RequestedClaims");
315            if (requestedClaims != null && !requestedClaims.isEmpty()) {
316                List list = new ArrayList();
317                list.addAll(requestedClaims);
318                claims = getClaims(list); 
319            }
320        }
321        
322        if(securityMech.equals(SecurityMechanism.STS_SECURITY_URI)) {
323           String useMetro = SystemConfigurationUtil.getProperty(
324                            "com.sun.identity.wss.trustclient.enablemetro",
325                            "true");
326           if(!(Boolean.valueOf(useMetro)).booleanValue()) {
327               return getSTSToken(wspEndPoint, stsEndPoint, stsMexEndPoint, 
328                   credential, keyTypeURI, tokenType, claims,
329                   wstVersion, stsAgentName); 
330           } else {
331               return getSTSToken(wspEndPoint,stsEndPoint,stsMexEndPoint,
332                   credential,keyTypeURI, tokenType, wstVersion,context); 
333           }
334        } else if (securityMech.equals(
335                SecurityMechanism.LIBERTY_DS_SECURITY_URI)) {
336           return getLibertyToken(pc, credential);
337        } else {
338           debug.error("TrustAuthorityClient.getSecurityToken" +
339                   "Invalid security mechanism to get token from TA");
340           return null;
341        }        
342        
343    }
344    
345    /**
346     * Renews the issued security token that was obtained from previous
347     * interactions with Security Token Service (STS).
348     * This method applies only for the STS Tokens.
349     * 
350     * In this current OpenSSO 8.0 release, this method implementation is not 
351     * supported.
352     * 
353     * @param securityToken security token that needs to be renewed.
354     * @param pc provider configuration of the web services client.
355     * @param credential User's credential. The user's credential could be
356     *        Single Sign-On Token or a SAML Assertion or any other object.     
357     * @return SecurityToken security token for the web services consumer.   
358     * @exception FAMSTSException if it's unable to renew security token or
359     *            if the trust authority configuration is not of STS.
360     */
361    public SecurityToken renewIssuedToken(SecurityToken securityToken,
362            ProviderConfig pc,            
363            Object credential) throws FAMSTSException {
364        //TODO To be implemented
365        throw new FAMSTSException("unsupported");
366        
367    }
368    
369    /**
370     * Cancels the issued security token that was obtained from previous 
371     * interactions with Security Token Service (STS).
372     * This method applies only for the STS Tokens.
373     * 
374     * In this current OpenSSO 8.0 release, this method implementation is not 
375     * supported.
376     * 
377     * @param securityToken security token that needs to be canceled.
378     * @param pc provider configuration of the web services client.
379     * @return true if succeed in cancelling the issued token.   
380     * @exception FAMSTSException if there is an exception in cancelling
381     *            issued security token or if the trust authority configuration
382     *            is not of STS.     
383     */
384    public boolean cancelIssuedToken(SecurityToken securityToken,
385            ProviderConfig pc) throws FAMSTSException {
386       // TODO - To be implemented
387        throw new FAMSTSException("unsupported");
388    }
389    
390    /**
391     * Returns security token obtained from Security Token Service.
392     */
393    private SecurityToken getSTSToken(String wspEndPoint,
394                                      String stsEndpoint,
395                                      String stsMexAddress,
396                                      Object credential,
397                                      String keyType,
398                                      String tokenType,
399                                      String wstVersion,
400                                      ServletContext context) 
401                                      throws FAMSTSException {
402        
403        if(debug.messageEnabled()) {
404            debug.message("TrustAuthorityClient.getSTSToken:: stsEndpoint : " 
405                + stsEndpoint);
406            debug.message("TrustAuthorityClient.getSTSToken:: stsMexAddress : " 
407                + stsMexAddress);
408            debug.message("TrustAuthorityClient.getSTSToken:: wsp end point : " 
409                + wspEndPoint);
410            debug.message("TrustAuthorityClient.getSTSToken:: keyType : " 
411                + keyType);
412        }
413
414        ClassLoader oldcc = Thread.currentThread().getContextClassLoader();        
415        try {                       
416            ClassLoader cls = 
417                       FAMClassLoader.getFAMClassLoader(context,jars);
418            Thread.currentThread().setContextClassLoader(cls);
419
420            Class _handlerTrustAuthorityClient = cls.loadClass(
421                       "com.sun.identity.wss.sts.TrustAuthorityClientImpl");
422
423            Constructor taClientCon = 
424                        _handlerTrustAuthorityClient.getConstructor();                
425
426            Object stsClient = taClientCon.newInstance();
427
428            Class clsa[] = new Class[7];
429            clsa[0] = Class.forName("java.lang.String");
430            clsa[1] = Class.forName("java.lang.String");
431            clsa[2] = Class.forName("java.lang.String");
432            clsa[3] = Class.forName("java.lang.Object");
433            clsa[4] = Class.forName("java.lang.String");
434            clsa[5] = Class.forName("java.lang.String");
435            clsa[6] = Class.forName("java.lang.String");
436
437            Method getSTSTokenElement = 
438                      stsClient.getClass().getDeclaredMethod(
439                      "getSTSTokenElement", clsa);
440
441            Object args[] = new Object[7];
442            args[0] = wspEndPoint;
443            args[1] = stsEndpoint;
444            args[2] = stsMexAddress;
445            args[3] = credential;
446            args[4] = keyType;
447            args[5] = tokenType;
448            args[6] = wstVersion;
449            Element element = (Element)getSTSTokenElement.invoke(stsClient, args);
450            String type = getTokenType(element);
451            
452            if(debug.messageEnabled()) {
453                debug.message("TrustAuthorityClient.getSTSToken:: Token "
454                    + "type : " + type);
455                debug.message("TrustAuthorityClient.getSTSToken:: Token"
456                    + " obtained from STS : " + XMLUtils.print(element));
457            }
458
459            if (LogUtil.isLogEnabled()) {
460                if (credential != null && (credential 
461                        instanceof com.iplanet.sso.SSOToken)) {
462                    String[] data = {wspEndPoint,stsEndpoint,stsMexAddress,
463                    credential.toString(),keyType,tokenType};
464                    LogUtil.access(Level.INFO,
465                            LogUtil.SUCCESS_RETRIEVING_TOKEN_FROM_STS,
466                            data,
467                            credential);
468                } else {
469                    String[] data2 = {wspEndPoint,stsEndpoint,stsMexAddress,
470                    null,keyType,tokenType};
471                    LogUtil.access(Level.INFO,
472                        LogUtil.SUCCESS_RETRIEVING_TOKEN_FROM_STS,
473                        data2,
474                        null);
475                }
476            }
477            
478            if (type != null) {
479                if (type.equals(STSConstants.SAML20_ASSERTION_TOKEN_TYPE)) {
480                    return new SAML2Token(element);
481                } else if (
482                    type.equals(STSConstants.SAML11_ASSERTION_TOKEN_TYPE)) {
483                    return new AssertionToken(element);    
484                } else if (type.equals(SecurityToken.WSS_FAM_SSO_TOKEN)) {
485                    return new FAMSecurityToken(element);
486                } else if (type.equals(SecurityToken.WSS_USERNAME_TOKEN)) {
487                    return new UserNameToken(element);
488                } else {
489                    throw new FAMSTSException (
490                            STSUtils.bundle.getString("unsupportedtokentype"));
491                }
492            } else {
493               throw new FAMSTSException (
494                       STSUtils.bundle.getString("nulltokentype"));
495            }
496
497        } catch (Exception ex) {
498            debug.error("TrustAuthorityClient.getSTSToken:: Failed in" +
499                "obtainining STS Token : ", ex);
500            String[] data = {ex.getLocalizedMessage()};
501            LogUtil.error(Level.INFO,
502                    LogUtil.ERROR_RETRIEVING_TOKEN_FROM_STS,
503                    data,
504                    null);
505            LogUtil.error(Level.SEVERE,
506                    LogUtil.ERROR_RETRIEVING_TOKEN_FROM_STS,
507                    data,
508                    null);
509            throw new FAMSTSException(
510                    STSUtils.bundle.getString("wstrustexception"));
511        } finally {
512            Thread.currentThread().setContextClassLoader(oldcc);
513        }
514
515    }
516    
517    /**
518     * Returns Liberty token by quering Liberty discovery service
519     */
520    private SecurityToken getLibertyToken(ProviderConfig pc,
521            Object ssoToken) throws FAMSTSException {
522        
523        // TODO - to be implemented
524        throw new FAMSTSException(
525                STSUtils.bundle.getString("unsupportedoperation"));
526    }
527    
528    private String getTokenType (Element element) throws FAMSTSException {
529        String elemName = element.getLocalName(); 
530        if (elemName == null) {
531            throw new FAMSTSException(
532                    STSUtils.bundle.getString("invalidelementname"));
533        }
534
535        if (elemName.equals(STSConstants.ASSERTION_ELEMENT)) {
536            String attrValue = element.getNamespaceURI();
537            if ((attrValue != null) && (attrValue.length() != 0) 
538                && (attrValue.equals(STSConstants.SAML20_ASSERTION)) ) {
539                return STSConstants.SAML20_ASSERTION_TOKEN_TYPE;
540            }
541            attrValue = element.getNamespaceURI();
542            if ((attrValue != null) && (attrValue.length() != 0) 
543                && (attrValue.equals(STSConstants.SAML10_ASSERTION)) ) {
544                return STSConstants.SAML11_ASSERTION_TOKEN_TYPE;
545            }            
546        } else if (elemName.equals(STSConstants.USER_NAME_TOKEN)) {
547            return SecurityToken.WSS_USERNAME_TOKEN;
548            
549        } else if(elemName.equals("FAMToken")) {
550            return SecurityToken.WSS_FAM_SSO_TOKEN;
551        } else {
552            // TBD for other token types.
553            return "getTokenType:NOT IMPLEMENTED TOKEN TYPE";
554        }
555        return null;
556    }
557    
558    private SecurityToken getSTSToken(String wspEndPoint,
559            String stsEndPoint,
560            String stsMexEndPoint,
561            Object credential, 
562            String keyType, 
563            String tokenType,
564            List claims,
565            String wstVersion,
566            String stsAgentName) throws FAMSTSException {
567        try {
568            if(debug.messageEnabled()) {
569               debug.message("TrustAuthorityClient.getSTSToken: WS-Trust" +
570                       " Parameters: " + "STSEndpoint = " + stsEndPoint +
571                       " keyType = " + keyType + " tokenType = " + tokenType +
572                       " wstVersion = " + wstVersion + 
573                       " STSAgentName = " + stsAgentName); 
574            }
575            WSTrustFactory trustFactory = 
576                                 WSTrustFactory.newInstance(wstVersion);
577            RequestSecurityToken rst = 
578                      trustFactory.createRequestSecurityToken();
579            rst.setAppliesTo(wspEndPoint);
580            rst.setKeyType(keyType);
581            
582            String requestType = STSConstants.WST10_NAMESPACE + "/Issue";
583            if(STSConstants.WST_VERSION_13.equals(wstVersion)) {
584               requestType = STSConstants.WST13_NAMESPACE + "/Issue"; 
585            }
586            rst.setRequestType(requestType);
587            if(credential != null) {
588               rst.setOnBehalfOf(getClientUserToken(credential));
589            }
590            rst.setTokenType(tokenType);
591            if(claims != null && !claims.isEmpty()) {
592               rst.setClaimTypes(claims); 
593            }
594            RequestSecurityTokenResponse rstR = 
595                   getTrustResponse(rst, stsEndPoint, stsAgentName, 
596                   wstVersion, credential);
597            RequestedProofToken reqProofToken = rstR.getRequestedProofToken();
598            if(reqProofToken != null) {
599               Object proofToken = reqProofToken.getProofToken();
600               if(proofToken instanceof BinarySecret) {
601                  BinarySecret binarySecret = 
602                          (BinarySecret)reqProofToken.getProofToken();
603                  if(binarySecret != null) {
604                     secretKey = binarySecret.getSecret();
605                  }
606               }//TODO handle encrypted key case. Not critical for now.
607               
608            }
609            Element secTokenE = 
610                    (Element)rstR.getRequestedSecurityToken().getFirstChild();
611            return parseSecurityToken(secTokenE);
612        } catch (WSTException wse) {
613            debug.error("TrustAuthorityClient.getSTSToken: Failed in " +
614                    " retrieving Token from STS", wse);
615           throw new FAMSTSException(wse.getMessage()); 
616        }
617        
618    }            
619     
620    private RequestSecurityTokenResponse getTrustResponse(
621            RequestSecurityToken rst,
622            String url,
623            String stsAgentName,
624            String wstVersion,
625            Object credential) throws FAMSTSException {
626        
627        SOAPMessage soapMsg = STSUtils.prepareSOAPMessage(url, wstVersion);
628        if(soapMsg == null) {
629           throw new FAMSTSException("nullElement"); 
630        }
631        try {            
632            Node rstE = soapMsg.getSOAPPart().importNode(
633                    rst.toDOMElement(), true);
634            soapMsg.getSOAPBody().appendChild(rstE);
635            SOAPRequestHandler handler = new SOAPRequestHandler();
636            Map config = new HashMap();
637            config.put("providername", stsAgentName);
638            QName serviceQName = new QName(stsAgentName);
639            config.put("javax.xml.ws.wsdl.service", serviceQName);
640            handler.init(config);            
641            Subject subject = new Subject();
642            if(credential != null) {
643               subject.getPrivateCredentials().add(credential);
644            }
645            SOAPMessage secureMsg = handler.secureRequest(
646                    soapMsg, subject, config);           
647            SOAPMessage response = getSOAPResponse(secureMsg, url);            
648            handler.validateResponse(response, config);
649            return getRequestSecurityTokenResponse(response, wstVersion);
650        } catch (SOAPException se) {
651            debug.error("TrustAuthorityClient.getTrustResponse: " +
652                    " SOAP Exception", se);
653            throw new FAMSTSException(se.getMessage());
654        } catch (WSTException we) {
655            debug.error("TrustAuthorityClient.getTrustResponse: " +
656                    " WST Exception", we);
657            throw new FAMSTSException(we.getMessage());
658        } catch (SecurityException sse) {
659            debug.error("TrustAuthorityClient.getTrustResponse: " +
660                    " SecurityException", sse);
661            throw new FAMSTSException(sse.getMessage());
662        }                        
663        
664    }
665    
666    private SOAPMessage getSOAPResponse(SOAPMessage soapMsg, String url)
667              throws FAMSTSException {
668        try {
669            SOAPClient soapClient = new SOAPClient();
670            soapClient.setURL(url);
671            String msg = XMLUtils.print(soapMsg.getSOAPPart(),"UTF-8");
672            InputStream is = soapClient.call(msg, null, null);
673            return STSUtils.createSOAPMessage(is);            
674        } catch (SOAPException se) {
675            debug.error("TrustAutorityClient.getSOAPResponse: " +
676                    " soap exception", se);
677            throw new FAMSTSException(se.getMessage());
678        } catch (Exception ex) {
679             debug.error("TrustAutorityClient.getSOAPResponse: " +
680                    "  exception", ex);
681            throw new FAMSTSException(ex.getMessage());
682        }
683    }
684    
685    private RequestSecurityTokenResponse getRequestSecurityTokenResponse(
686            SOAPMessage soapMsg, String wstVersion) throws FAMSTSException {
687        try {
688            Element rstRC = (Element)soapMsg.getSOAPBody().getFirstChild();
689            WSTrustFactory wstFactory =  WSTrustFactory.newInstance(wstVersion);
690            if("RequestSecurityTokenResponse".equals(rstRC.getLocalName())) {
691               return wstFactory.createRequestSecurityTokenResponse(rstRC); 
692            }
693            RequestSecurityTokenResponseCollection rstRCollection = 
694                 wstFactory.createRequestSecurityTokenResponseCollection(rstRC);
695            List rstResponses = 
696                    rstRCollection.getRequestSecurityTokenResponses();
697            if(rstResponses.size() == 0) {
698               throw new FAMSTSException("nullElements");
699            }
700            return (RequestSecurityTokenResponse)rstResponses.get(0);
701            
702        } catch (SOAPException se) {
703            debug.error("TrustAuthorityClient.getRequestSecurityTokenResponse:"
704                    + " soap exception", se);
705            throw new FAMSTSException(se.getMessage());
706        } catch (WSTException we) {
707            debug.error("TrustAuthorityClient.getRequestSecurityTokenResponse:"
708                    + " wst exception", we);
709            throw new FAMSTSException(we.getMessage());
710        }
711    }
712    
713    private SecurityToken parseSecurityToken(Element element) 
714            throws FAMSTSException {
715        String type = getTokenType(element);
716        try {
717            if (type != null) {
718                if (type.equals(STSConstants.SAML20_ASSERTION_TOKEN_TYPE)) {
719                    return new SAML2Token(element);
720                } else if (
721                    type.equals(STSConstants.SAML11_ASSERTION_TOKEN_TYPE)) {
722                    return new AssertionToken(element);    
723                } else if (type.equals(SecurityToken.WSS_FAM_SSO_TOKEN)) {
724                    return new FAMSecurityToken(element);
725                } else if (type.equals(SecurityToken.WSS_USERNAME_TOKEN)) {
726                    return new UserNameToken(element);
727                } else {
728                    throw new FAMSTSException (
729                            STSUtils.bundle.getString("unsupportedtokentype"));
730                }
731            } else {
732               throw new FAMSTSException (
733                       STSUtils.bundle.getString("nulltokentype"));
734            }
735        } catch (Exception se) {
736            debug.error("TrustAuthorityClient.parseSecurityToken: " +
737                    "Exception :", se);
738            throw new FAMSTSException(se.getMessage());
739        }
740            
741        
742    }
743    
744    /**
745     * Returns the secret key obtained as a proof token from STS.
746     * This is available only when the requested token type is symmetric.
747     * @return the secret key obtained from STS.
748     */
749    public Key getSecretKey() {
750        if(secretKey == null) {
751           return null;
752        }
753        return new SecretKeySpec(secretKey, "AES");
754    }
755    
756    private Element getClientUserToken(Object credential) 
757                throws FAMSTSException {
758        if (clientTokenClass == null) {
759            String className =   SystemConfigurationUtil.getProperty(
760                STSConstants.STS_CLIENT_USER_TOKEN_PLUGIN, 
761                "com.sun.identity.wss.sts.STSClientUserToken");
762            try {                
763                clientTokenClass = 
764                       (Thread.currentThread().getContextClassLoader()).
765                        loadClass(className);                               
766            } catch (Exception ex) {
767                 debug.error("TrustAuthorityClientImpl.getClientUserToken:"
768                           +  "Failed in obtaining class", ex);
769                 throw new FAMSTSException(
770                       STSUtils.bundle.getString("initializationFailed"));
771            }
772        }
773        
774        try {
775            ClientUserToken userToken =
776                (ClientUserToken) clientTokenClass.newInstance();
777            userToken.init(credential);
778            if(debug.messageEnabled()) {
779                debug.message("TrustAuthorityClientImpl:getClientUserToken: " + 
780                    "Client User Token : " + userToken);
781            }
782            return (Element)userToken.getTokenValue();
783
784        } catch (Exception ex) {
785            debug.error("TrustAuthorityClientImpl.getClientUserToken: " +
786                 "Failed in initialization", ex);
787             throw new FAMSTSException(
788                     STSUtils.bundle.getString("usertokeninitfailed"));
789        }
790    }
791    
792    private List<ClaimType> getClaims(List<String> requestedClaims) {
793        List<ClaimType> claimTypes = new ArrayList<ClaimType>();
794        Iterator<String> iter = requestedClaims.iterator();
795        while(iter.hasNext()) {
796            String claimName = iter.next();
797            ClaimType claimType = new ClaimType(ClaimType.IDENTITY_NS);
798            claimType.setName(claimName);
799            claimTypes.add(claimType);
800        }
801        return claimTypes;
802    }
803            
804    /**
805     * The list of jar files to be loaded by FAMClassLoader.
806     */
807    public static String[] jars = new String[]{
808        "webservices-api.jar",
809        "webservices-rt.jar",
810        "webservices-tools.jar",
811        "webservices-extra-api.jar",
812        "webservices-extra.jar",
813        "openssoclientsdk.jar",
814        "openssowssproviders.jar",
815        "xalan.jar",
816        "xercesImpl.jar"
817    };        
818}