1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.misc;
21  
22  import org.apache.ws.security.SAMLTokenPrincipal;
23  import org.apache.ws.security.WSSConfig;
24  import org.apache.ws.security.WSSecurityEngineResult;
25  import org.apache.ws.security.WSSecurityEngine;
26  import org.apache.ws.security.WSConstants;
27  import org.apache.ws.security.WSSecurityException;
28  import org.apache.ws.security.WSUsernameTokenPrincipal;
29  import org.apache.ws.security.common.SAML1CallbackHandler;
30  import org.apache.ws.security.common.SAML2CallbackHandler;
31  import org.apache.ws.security.common.UsernamePasswordCallbackHandler;
32  import org.apache.ws.security.common.SOAPUtil;
33  import org.apache.ws.security.components.crypto.Crypto;
34  import org.apache.ws.security.components.crypto.CryptoFactory;
35  import org.apache.ws.security.components.crypto.CryptoType;
36  import org.apache.ws.security.handler.RequestData;
37  import org.apache.ws.security.message.WSSecHeader;
38  import org.apache.ws.security.message.WSSecSAMLToken;
39  import org.apache.ws.security.message.WSSecUsernameToken;
40  import org.apache.ws.security.message.token.BinarySecurity;
41  import org.apache.ws.security.message.token.X509Security;
42  import org.apache.ws.security.saml.ext.AssertionWrapper;
43  import org.apache.ws.security.saml.ext.SAMLParms;
44  import org.apache.ws.security.util.WSSecurityUtil;
45  import org.apache.ws.security.validate.Credential;
46  import org.apache.ws.security.validate.Validator;
47  import org.w3c.dom.Document;
48  
49  import javax.security.auth.callback.CallbackHandler;
50  import javax.xml.namespace.QName;
51  
52  import java.security.Principal;
53  import java.security.cert.X509Certificate;
54  import java.util.List;
55  
56  /**
57   * Test various principal objects after processing a security token.
58   */
59  public class PrincipalTest extends org.junit.Assert {
60      private static final org.apache.commons.logging.Log LOG = 
61          org.apache.commons.logging.LogFactory.getLog(PrincipalTest.class);
62      
63      private CallbackHandler callbackHandler = new UsernamePasswordCallbackHandler();
64  
65      /**
66       * Test the principal that is created after processing a Username Token
67       */
68      @org.junit.Test
69      public void testUsernameToken() throws Exception {
70          WSSecUsernameToken builder = new WSSecUsernameToken();
71          builder.setUserInfo("wernerd", "verySecret");
72          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
73          WSSecHeader secHeader = new WSSecHeader();
74          secHeader.insertSecurityHeader(doc);
75          Document signedDoc = builder.build(doc, secHeader);
76  
77          if (LOG.isDebugEnabled()) {
78              String outputString = 
79                  org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
80              LOG.debug(outputString);
81          }
82          List<WSSecurityEngineResult> results = verify(signedDoc, null);
83          
84          Principal principal = (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
85          assertTrue(principal instanceof WSUsernameTokenPrincipal);
86          assertTrue("wernerd".equals(principal.getName()));
87          WSUsernameTokenPrincipal userPrincipal = (WSUsernameTokenPrincipal)principal;
88          assertTrue(userPrincipal.getCreatedTime() != null);
89          assertTrue(userPrincipal.getNonce() != null);
90          assertTrue(userPrincipal.getPassword() != null);
91          assertTrue(userPrincipal.isPasswordDigest());
92          assertTrue(WSConstants.PASSWORD_DIGEST.equals(userPrincipal.getPasswordType()));
93      }
94      
95      /**
96       * Test the principal that is created after processing a Username Token, which has been
97       * transformed into a SAML Assertion.
98       */
99      @org.junit.Test
100     public void testTransformedUsernameToken() throws Exception {
101         WSSecUsernameToken builder = new WSSecUsernameToken();
102         builder.setUserInfo("wernerd", "verySecret");
103         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
104         WSSecHeader secHeader = new WSSecHeader();
105         secHeader.insertSecurityHeader(doc);
106         Document signedDoc = builder.build(doc, secHeader);
107 
108         if (LOG.isDebugEnabled()) {
109             String outputString = 
110                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
111             LOG.debug(outputString);
112         }
113         List<WSSecurityEngineResult> results = 
114             verify(signedDoc, new DummyValidator(), WSSecurityEngine.USERNAME_TOKEN, null);
115         
116         Principal principal = (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
117         assertTrue(principal instanceof SAMLTokenPrincipal);
118         assertTrue(principal.getName().contains("uid=joe"));
119         assertTrue(((SAMLTokenPrincipal)principal).getToken() != null);
120     }
121     
122     /**
123      * Test the principal that is created after processing a SAML Token
124      */
125     @org.junit.Test
126     public void testSAMLToken() throws Exception {
127         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
128         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
129         callbackHandler.setIssuer("www.example.com");
130         
131         SAMLParms samlParms = new SAMLParms();
132         samlParms.setCallbackHandler(callbackHandler);
133         AssertionWrapper assertion = new AssertionWrapper(samlParms);
134 
135         WSSecSAMLToken wsSign = new WSSecSAMLToken();
136 
137         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
138         WSSecHeader secHeader = new WSSecHeader();
139         secHeader.insertSecurityHeader(doc);
140         
141         Document unsignedDoc = wsSign.build(doc, assertion, secHeader);
142 
143         if (LOG.isDebugEnabled()) {
144             String outputString = 
145                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(unsignedDoc);
146             LOG.debug(outputString);
147         }
148         
149         List<WSSecurityEngineResult> results = verify(unsignedDoc, null);
150         WSSecurityEngineResult actionResult =
151             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
152         AssertionWrapper receivedAssertion = 
153             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
154         assertTrue(receivedAssertion != null);
155         
156         Principal principal = 
157             (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
158         assertTrue(principal instanceof SAMLTokenPrincipal);
159         assertTrue(principal.getName().contains("uid=joe"));
160         assertTrue(((SAMLTokenPrincipal)principal).getToken() != null);
161     }
162     
163     /**
164      * Test the principal that is created after processing a SAML2 Token
165      */
166     @org.junit.Test
167     public void testSAML2Token() throws Exception {
168         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
169         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
170         callbackHandler.setIssuer("www.example.com");
171         
172         SAMLParms samlParms = new SAMLParms();
173         samlParms.setCallbackHandler(callbackHandler);
174         AssertionWrapper assertion = new AssertionWrapper(samlParms);
175 
176         WSSecSAMLToken wsSign = new WSSecSAMLToken();
177 
178         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
179         WSSecHeader secHeader = new WSSecHeader();
180         secHeader.insertSecurityHeader(doc);
181         
182         Document unsignedDoc = wsSign.build(doc, assertion, secHeader);
183 
184         if (LOG.isDebugEnabled()) {
185             String outputString = 
186                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(unsignedDoc);
187             LOG.debug(outputString);
188         }
189         
190         List<WSSecurityEngineResult> results = verify(unsignedDoc, null);
191         WSSecurityEngineResult actionResult =
192             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
193         AssertionWrapper receivedAssertion = 
194             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
195         assertTrue(receivedAssertion != null);
196         
197         Principal principal = 
198             (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
199         assertTrue(principal instanceof SAMLTokenPrincipal);
200         assertTrue(principal.getName().contains("uid=joe"));
201         assertTrue(((SAMLTokenPrincipal)principal).getToken() != null);
202     }
203     
204     /**
205      * Test the principal that is created after processing a SAML Token, which has been
206      * transformed into another SAML Token.
207      */
208     @org.junit.Test
209     public void testTransformedSAMLToken() throws Exception {
210         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
211         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
212         callbackHandler.setIssuer("www.example.com");
213         
214         SAMLParms samlParms = new SAMLParms();
215         samlParms.setCallbackHandler(callbackHandler);
216         AssertionWrapper assertion = new AssertionWrapper(samlParms);
217 
218         WSSecSAMLToken wsSign = new WSSecSAMLToken();
219 
220         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
221         WSSecHeader secHeader = new WSSecHeader();
222         secHeader.insertSecurityHeader(doc);
223         
224         Document unsignedDoc = wsSign.build(doc, assertion, secHeader);
225 
226         if (LOG.isDebugEnabled()) {
227             String outputString = 
228                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(unsignedDoc);
229             LOG.debug(outputString);
230         }
231         
232         List<WSSecurityEngineResult> results = 
233             verify(unsignedDoc, new DummyValidator(), WSSecurityEngine.SAML_TOKEN, null);
234         WSSecurityEngineResult actionResult =
235             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
236         AssertionWrapper receivedAssertion = 
237             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
238         assertTrue(receivedAssertion != null);
239         
240         Principal principal = 
241             (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
242         assertTrue(principal instanceof SAMLTokenPrincipal);
243         assertTrue(principal.getName().contains("uid=joe"));
244         assertTrue(((SAMLTokenPrincipal)principal).getToken() != null);
245     }
246     
247     /**
248      * Test the principal that is created after processing (and explicitly validating)
249      * a BinarySecurityToken.
250      */
251     @org.junit.Test
252     public void testBinarySecurityToken() throws Exception {
253         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
254 
255         WSSecHeader secHeader = new WSSecHeader();
256         secHeader.insertSecurityHeader(doc);
257         
258         X509Security bst = new X509Security(doc);
259         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
260         cryptoType.setAlias("wss40");
261         Crypto crypto = CryptoFactory.getInstance("wss40.properties");
262         X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
263         bst.setX509Certificate(certs[0]);
264         
265         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
266         
267         if (LOG.isDebugEnabled()) {
268             String outputString = 
269                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
270             LOG.debug(outputString);
271         }
272         
273         List<WSSecurityEngineResult> results = 
274             verify(doc, new DummyValidator(), WSSecurityEngine.BINARY_TOKEN, crypto);
275         WSSecurityEngineResult actionResult =
276             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
277         BinarySecurity token =
278             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
279         assertNotNull(token);
280         
281         Principal principal = 
282             (Principal)results.get(0).get(WSSecurityEngineResult.TAG_PRINCIPAL);
283         assertTrue(principal instanceof SAMLTokenPrincipal);
284         assertTrue(principal.getName().contains("uid=joe"));
285         assertTrue(((SAMLTokenPrincipal)principal).getToken() != null);
286     }
287     
288     /**
289      * Verifies the soap envelope
290      */
291     private List<WSSecurityEngineResult> verify(
292         Document doc,
293         Crypto crypto
294     ) throws Exception {
295         return verify(doc, null, null, crypto);
296     }
297     
298     /**
299      * Verifies the soap envelope
300      */
301     private List<WSSecurityEngineResult> verify(
302         Document doc, 
303         Validator validator,
304         QName validatorName,
305         Crypto crypto
306     ) throws Exception {
307         WSSConfig config = WSSConfig.getNewInstance();
308         WSSecurityEngine secEngine = new WSSecurityEngine();
309         secEngine.setWssConfig(config);
310         if (validator != null && validatorName != null) {
311             config.setValidator(validatorName, validator);
312         }
313         return secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
314     }
315     
316     /**
317      * A Dummy Validator instance that just creates a new SAML Assertion, ignoring the
318      * credential it has been passed.
319      */
320     private static class DummyValidator implements Validator {
321 
322         public Credential validate(Credential credential, RequestData data) throws WSSecurityException {
323             try {
324                 SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
325                 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
326                 callbackHandler.setIssuer("www.example.com");
327                 
328                 SAMLParms samlParms = new SAMLParms();
329                 samlParms.setCallbackHandler(callbackHandler);
330                 AssertionWrapper assertion = new AssertionWrapper(samlParms);
331     
332                 credential.setTransformedToken(assertion);
333                 return credential;
334             } catch (Exception ex) {
335                 throw new WSSecurityException(WSSecurityException.FAILURE);
336             }
337         }
338         
339     }
340 }