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 org.apache.wss4j.dom.common;
21  
22  import org.apache.wss4j.dom.WSConstants;
23  import org.apache.wss4j.common.crypto.Crypto;
24  import org.apache.wss4j.common.saml.SAMLCallback;
25  import org.apache.wss4j.common.saml.bean.ActionBean;
26  import org.apache.wss4j.common.saml.bean.AttributeBean;
27  import org.apache.wss4j.common.saml.bean.AttributeStatementBean;
28  import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean;
29  import org.apache.wss4j.common.saml.bean.AuthenticationStatementBean;
30  import org.apache.wss4j.common.saml.bean.ConditionsBean;
31  import org.apache.wss4j.common.saml.bean.KeyInfoBean;
32  import org.apache.wss4j.common.saml.bean.KeyInfoBean.CERT_IDENTIFIER;
33  import org.apache.wss4j.common.util.KeyUtils;
34  import org.apache.wss4j.common.saml.bean.NameIDBean;
35  import org.apache.wss4j.common.saml.bean.SubjectBean;
36  import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
37  import org.apache.wss4j.common.saml.bean.SubjectLocalityBean;
38  import org.apache.wss4j.dom.message.WSSecEncryptedKey;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  
42  import javax.crypto.KeyGenerator;
43  import javax.crypto.SecretKey;
44  import javax.security.auth.callback.CallbackHandler;
45  import javax.xml.parsers.DocumentBuilder;
46  import javax.xml.parsers.DocumentBuilderFactory;
47  
48  import java.security.cert.X509Certificate;
49  import java.time.Instant;
50  import java.util.ArrayList;
51  import java.util.Collections;
52  import java.util.List;
53  
54  /**
55   * A base implementation of a Callback Handler for a SAML assertion. By default it creates an
56   * authentication assertion.
57   */
58  public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
59  
60      public enum Statement {
61          AUTHN, ATTR, AUTHZ
62      }
63  
64      protected String subjectName;
65      protected String subjectQualifier;
66      protected String confirmationMethod;
67      protected X509Certificate[] certs;
68      protected Statement statement = Statement.AUTHN;
69      protected CERT_IDENTIFIER certIdentifier = CERT_IDENTIFIER.X509_CERT;
70      protected byte[] ephemeralKey;
71      protected String issuer;
72      protected String issuerFormat;
73      protected String subjectNameIDFormat;
74      protected String subjectLocalityIpAddress;
75      protected String subjectLocalityDnsAddress;
76      protected Instant sessionNotOnOrAfter;
77      protected Instant authenticationInstant;
78      protected String resource;
79      protected List<Object> customAttributeValues;
80      protected ConditionsBean conditions;
81      protected SubjectConfirmationDataBean subjectConfirmationData;
82      private Crypto issuerCrypto;
83      private String issuerName;
84      private String issuerPassword;
85      private Element assertionAdviceElement;
86      private Element keyInfoElement;
87      protected NameIDBean subjectConfirmationNameID;
88      protected boolean signAssertion;
89  
90      public boolean isSignAssertion() {
91          return signAssertion;
92      }
93  
94      public void setSignAssertion(boolean signAssertion) {
95          this.signAssertion = signAssertion;
96      }
97  
98      public void setSubjectName(String subjectName) {
99          this.subjectName = subjectName;
100     }
101 
102     public NameIDBean getSubjectConfirmationNameID() {
103         return subjectConfirmationNameID;
104     }
105 
106     public void setSubjectConfirmationNameID(NameIDBean subjectConfirmationNameID) {
107         this.subjectConfirmationNameID = subjectConfirmationNameID;
108     }
109 
110     public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
111         this.subjectConfirmationData = subjectConfirmationData;
112     }
113 
114     public void setConditions(ConditionsBean conditionsBean) {
115         this.conditions = conditionsBean;
116     }
117 
118     public void setConfirmationMethod(String confMethod) {
119         confirmationMethod = confMethod;
120     }
121 
122     public void setSessionNotOnOrAfter(Instant sessionNotOnOrAfter) {
123         this.sessionNotOnOrAfter = sessionNotOnOrAfter;
124     }
125 
126     public void setStatement(Statement statement) {
127         this.statement = statement;
128     }
129 
130     public void setCertIdentifier(CERT_IDENTIFIER certIdentifier) {
131         this.certIdentifier = certIdentifier;
132     }
133 
134     public void setCerts(X509Certificate[] certs) {
135         this.certs = certs;
136     }
137 
138     public byte[] getEphemeralKey() {
139         return ephemeralKey;
140     }
141 
142     public void setIssuer(String issuer) {
143         this.issuer = issuer;
144     }
145 
146     public void setIssuerFormat(String issuerFormat) {
147         this.issuerFormat = issuerFormat;
148     }
149 
150     public void setSubjectNameIDFormat(String subjectNameIDFormat) {
151         this.subjectNameIDFormat = subjectNameIDFormat;
152     }
153 
154     public void setSubjectLocality(String ipAddress, String dnsAddress) {
155         this.subjectLocalityIpAddress = ipAddress;
156         this.subjectLocalityDnsAddress = dnsAddress;
157     }
158 
159     public void setResource(String resource) {
160         this.resource = resource;
161     }
162 
163     public void setCustomAttributeValues(List<Object> customAttributeValues) {
164         this.customAttributeValues = customAttributeValues;
165     }
166 
167     public Instant getAuthenticationInstant() {
168         return authenticationInstant;
169     }
170 
171     public void setAuthenticationInstant(Instant authenticationInstant) {
172         this.authenticationInstant = authenticationInstant;
173     }
174 
175     /**
176      * Note that the SubjectBean parameter should be null for SAML2.0
177      */
178     protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback callback) {
179         if (statement == Statement.AUTHN) {
180             AuthenticationStatementBean authBean = new AuthenticationStatementBean();
181             if (subjectBean != null) {
182                 authBean.setSubject(subjectBean);
183             }
184             if (subjectLocalityIpAddress != null || subjectLocalityDnsAddress != null) {
185                 SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
186                 subjectLocality.setIpAddress(subjectLocalityIpAddress);
187                 subjectLocality.setDnsAddress(subjectLocalityDnsAddress);
188                 authBean.setSubjectLocality(subjectLocality);
189             }
190             authBean.setAuthenticationMethod("Password");
191             authBean.setAuthenticationInstant(authenticationInstant);
192             authBean.setSessionNotOnOrAfter(sessionNotOnOrAfter);
193             callback.setAuthenticationStatementData(Collections.singletonList(authBean));
194         } else if (statement == Statement.ATTR) {
195             AttributeStatementBean attrBean = new AttributeStatementBean();
196             AttributeBean attributeBean = new AttributeBean();
197             if (subjectBean != null) {
198                 attrBean.setSubject(subjectBean);
199                 attributeBean.setSimpleName("role");
200                 attributeBean.setQualifiedName("http://custom-ns");
201             } else {
202                 attributeBean.setQualifiedName("role");
203             }
204             if (customAttributeValues != null) {
205                 attributeBean.setAttributeValues(customAttributeValues);
206             } else {
207                 List<Object> attributes = new ArrayList<>();
208                 attributes.add("user");
209                 attributeBean.setAttributeValues(attributes);
210             }
211             attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
212             callback.setAttributeStatementData(Collections.singletonList(attrBean));
213         } else {
214             AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean();
215             if (subjectBean != null) {
216                 authzBean.setSubject(subjectBean);
217             }
218             ActionBean actionBean = new ActionBean();
219             actionBean.setContents("Read");
220             authzBean.setActions(Collections.singletonList(actionBean));
221             authzBean.setResource("endpoint");
222             authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT);
223             authzBean.setResource(resource);
224             callback.setAuthDecisionStatementData(Collections.singletonList(authzBean));
225         }
226     }
227 
228     protected KeyInfoBean createKeyInfo() throws Exception {
229         KeyInfoBean keyInfo = new KeyInfoBean();
230         if (keyInfoElement != null) {
231             keyInfo.setElement(keyInfoElement);
232         } else if (statement == Statement.AUTHN) {
233             keyInfo.setCertificate(certs[0]);
234             keyInfo.setCertIdentifer(certIdentifier);
235         } else if (statement == Statement.ATTR) {
236             // Build a new Document
237             DocumentBuilderFactory docBuilderFactory =
238                 DocumentBuilderFactory.newInstance();
239             docBuilderFactory.setNamespaceAware(true);
240             DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
241             Document doc = docBuilder.newDocument();
242 
243             // Create an Encrypted Key
244             WSSecEncryptedKey encrKey = new WSSecEncryptedKey(doc);
245             encrKey.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
246             encrKey.setUseThisCert(certs[0]);
247 
248             KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
249             SecretKey symmetricKey = keyGen.generateKey();
250             encrKey.prepare(null, symmetricKey);
251             ephemeralKey = symmetricKey.getEncoded();
252             Element encryptedKeyElement = encrKey.getEncryptedKeyElement();
253 
254             // Append the EncryptedKey to a KeyInfo element
255             Element kiElement =
256                 doc.createElementNS(
257                     WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
258                 );
259             kiElement.setAttributeNS(
260                 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
261             );
262             kiElement.appendChild(encryptedKeyElement);
263 
264             keyInfo.setElement(kiElement);
265         }
266         return keyInfo;
267     }
268 
269     public Crypto getIssuerCrypto() {
270         return issuerCrypto;
271     }
272 
273     public void setIssuerCrypto(Crypto issuerCrypto) {
274         this.issuerCrypto = issuerCrypto;
275     }
276 
277     public String getIssuerName() {
278         return issuerName;
279     }
280 
281     public void setIssuerName(String issuerName) {
282         this.issuerName = issuerName;
283     }
284 
285     public String getIssuerPassword() {
286         return issuerPassword;
287     }
288 
289     public void setIssuerPassword(String issuerPassword) {
290         this.issuerPassword = issuerPassword;
291     }
292 
293     public Element getAssertionAdviceElement() {
294         return assertionAdviceElement;
295     }
296 
297     public void setAssertionAdviceElement(Element assertionAdviceElement) {
298         this.assertionAdviceElement = assertionAdviceElement;
299     }
300 
301     public Element getKeyInfoElement() {
302         return keyInfoElement;
303     }
304 
305     public void setKeyInfoElement(Element keyInfoElement) {
306         this.keyInfoElement = keyInfoElement;
307     }
308 }