View Javadoc

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 dk.sosi.seal.transform.internal;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.ws.security.WSConstants;
25  import org.apache.ws.security.WSDocInfo;
26  import org.apache.ws.security.WSSecurityException;
27  import org.apache.ws.security.message.token.X509Security;
28  import org.apache.ws.security.util.Base64;
29  import org.apache.ws.security.util.WSSecurityUtil;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Text;
33  
34  import java.security.cert.CertificateEncodingException;
35  import java.security.cert.X509Certificate;
36  
37  /**
38   * Utility class exposing the dereferencing logic of the {@link STRTransform} implementation.
39   */
40  public class STRTransformUtil {
41      private static Log log = LogFactory.getLog(STRTransformUtil.class.getName());
42  
43      /**
44       * Retrieves the element representing the referenced content of a STR.
45       * 
46       * @return the element representing the referenced content. The element is either
47       *         extracted from {@code doc} or a new element is created in the
48       *         case of a key identifier or issuer serial STR.  {@code null} if
49       *         {@code secRef} does not contain a direct reference, key identifier, or
50       *         issuer serial.
51       * @throws WSSecurityException
52       *             If an issuer serial or key identifier is used in the STR and
53       *             the certificate cannot be resolved from the crypto
54       *             configuration or if there is an error working with the resolved
55       *             cert
56       */
57      public static Element dereferenceSTR(Document doc,
58              SecurityTokenReference secRef, WSDocInfo wsDocInfo) throws WSSecurityException
59      {
60          
61          // NOTE: Here step numbers refer to the overall step in the complete processing
62          // of the STRTransform.  See STRTransform for the lead up to these steps.
63          //
64          // Third step: locate the security token referenced by the STR element.
65          // Either the Token is contained in the document as a
66          // BinarySecurityToken or stored in some key storage.
67          // 
68          // Fourth step: after security token was located, prepare it. If its
69          // reference via a direct reference, i.e. a relative URI that references
70          // the BST directly in the message then just return that element.
71          // Otherwise wrap the located token in a newly created BST element as
72          // described in WSS Specification.
73          // 
74          //
75          Element tokElement = null;
76      
77          //
78          // First case: direct reference, according to chap 7.2 of OASIS WS
79          // specification (main document). Only in this case return a true
80          // reference to the BST. Copying is done by the caller.
81          //
82          if (secRef.containsReference()) {
83              if (log.isDebugEnabled()) {
84                  log.debug("STR: Reference");
85              }
86              tokElement = secRef.getTokenElement(doc, wsDocInfo, null);
87          }
88          //
89          // second case: IssuerSerial, lookup in keystore, wrap in BST according
90          // to specification
91          //
92          else if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) {
93              if (log.isDebugEnabled()) {
94                  log.debug("STR: IssuerSerial");
95              }
96              X509Certificate cert = null;
97              X509Certificate[] certs = 
98                  secRef.getX509IssuerSerial(wsDocInfo.getCrypto());
99              if (certs == null || certs.length == 0 || certs[0] == null) {
100                 throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
101             }
102             cert = certs[0];
103             tokElement = createBSTX509(doc, cert, secRef.getElement());
104         }
105         //
106         // third case: KeyIdentifier. For SKI, lookup in keystore, wrap in
107         // BST according to specification. Otherwise if it's a wsse:KeyIdentifier it could
108         // be a SAML assertion, so try and find the referenced element.
109         //
110         else if (secRef.containsKeyIdentifier()) {
111             if (log.isDebugEnabled()) {
112                 log.debug("STR: KeyIdentifier");
113             }
114             if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())
115                     // Start added by Seal
116                     || WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())
117                     // End added by Seal
118                     ) {
119                 tokElement = secRef.getKeyIdentifierTokenElement(doc, wsDocInfo, null);
120             } else {
121                 X509Certificate cert = null;
122                 X509Certificate[] certs = secRef.getKeyIdentifier(wsDocInfo.getCrypto());
123                 if (certs == null || certs.length == 0 || certs[0] == null) {
124                     throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
125                 }
126                 cert = certs[0];
127                 tokElement = createBSTX509(doc, cert, secRef.getElement());
128             }
129         }
130         return tokElement;
131     }
132     
133     protected static Element createBSTX509(Document doc, X509Certificate cert, Element secRefE) 
134         throws WSSecurityException {
135         byte data[];
136         try {
137             data = cert.getEncoded();
138         } catch (CertificateEncodingException e) {
139             throw new WSSecurityException(
140                 WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "encodeError", null, e
141             );
142         }
143         String prefix = WSSecurityUtil.getPrefixNS(WSConstants.WSSE_NS, secRefE);
144         Element elem = doc.createElementNS(WSConstants.WSSE_NS, prefix + ":BinarySecurityToken");
145         WSSecurityUtil.setNamespace(elem, WSConstants.WSSE_NS, prefix);
146         // elem.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", "");
147         elem.setAttributeNS(null, "ValueType", X509Security.X509_V3_TYPE);
148         Text certText = doc.createTextNode(Base64.encode(data)); // no line wrap
149         elem.appendChild(certText);
150         return elem;
151     }
152     
153     /**
154      * Hidden in utility class.
155      */
156     private STRTransformUtil() {   
157     }
158     
159 }