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.common;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.message.WSSecEncryptedKey;
24  import org.apache.ws.security.saml.ext.SAMLCallback;
25  import org.apache.ws.security.saml.ext.bean.ActionBean;
26  import org.apache.ws.security.saml.ext.bean.AttributeBean;
27  import org.apache.ws.security.saml.ext.bean.AttributeStatementBean;
28  import org.apache.ws.security.saml.ext.bean.AuthenticationStatementBean;
29  import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean;
30  import org.apache.ws.security.saml.ext.bean.ConditionsBean;
31  import org.apache.ws.security.saml.ext.bean.KeyInfoBean;
32  import org.apache.ws.security.saml.ext.bean.SubjectBean;
33  import org.apache.ws.security.saml.ext.bean.SubjectConfirmationDataBean;
34  import org.apache.ws.security.saml.ext.bean.SubjectLocalityBean;
35  import org.apache.ws.security.saml.ext.bean.KeyInfoBean.CERT_IDENTIFIER;
36  import org.w3c.dom.Document;
37  import org.w3c.dom.Element;
38  
39  import javax.security.auth.callback.CallbackHandler;
40  import javax.xml.parsers.DocumentBuilder;
41  import javax.xml.parsers.DocumentBuilderFactory;
42  
43  import java.security.cert.X509Certificate;
44  import java.util.Collections;
45  import java.util.List;
46  
47  /**
48   * A base implementation of a Callback Handler for a SAML assertion. By default it creates an
49   * authentication assertion.
50   */
51  public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
52      
53      public enum Statement {
54          AUTHN, ATTR, AUTHZ
55      };
56      
57      protected String subjectName = null;
58      protected String subjectQualifier = null;
59      protected String confirmationMethod = null;
60      protected X509Certificate[] certs;
61      protected Statement statement = Statement.AUTHN;
62      protected CERT_IDENTIFIER certIdentifier = CERT_IDENTIFIER.X509_CERT;
63      protected byte[] ephemeralKey = null;
64      protected String issuer = null;
65      protected String subjectNameIDFormat = null;
66      protected String subjectLocalityIpAddress = null;
67      protected String subjectLocalityDnsAddress = null;
68      protected String resource = null;
69      protected List<?> customAttributeValues = null;
70      protected ConditionsBean conditions = null;
71      protected SubjectConfirmationDataBean subjectConfirmationData = null;
72      
73      public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
74          this.subjectConfirmationData = subjectConfirmationData;
75      }
76      
77      public void setConditions(ConditionsBean conditionsBean) {
78          this.conditions = conditionsBean;
79      }
80      
81      public void setConfirmationMethod(String confMethod) {
82          confirmationMethod = confMethod;
83      }
84      
85      public void setStatement(Statement statement) {
86          this.statement = statement;
87      }
88      
89      public void setCertIdentifier(CERT_IDENTIFIER certIdentifier) {
90          this.certIdentifier = certIdentifier;
91      }
92      
93      public void setCerts(X509Certificate[] certs) {
94          this.certs = certs;
95      }
96      
97      public byte[] getEphemeralKey() {
98          return ephemeralKey;
99      }
100     
101     public void setIssuer(String issuer) {
102         this.issuer = issuer;
103     }
104     
105     public void setSubjectNameIDFormat(String subjectNameIDFormat) {
106         this.subjectNameIDFormat = subjectNameIDFormat;
107     }
108     
109     public void setSubjectLocality(String ipAddress, String dnsAddress) {
110         this.subjectLocalityIpAddress = ipAddress;
111         this.subjectLocalityDnsAddress = dnsAddress;
112     }
113     
114     public void setResource(String resource) {
115         this.resource = resource;
116     }
117     
118     public void setCustomAttributeValues(List<?> customAttributeValues) {
119         this.customAttributeValues = customAttributeValues;
120     }
121     
122     /**
123      * Note that the SubjectBean parameter should be null for SAML2.0
124      */
125     protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback callback) {
126         if (statement == Statement.AUTHN) {
127             AuthenticationStatementBean authBean = new AuthenticationStatementBean();
128             if (subjectBean != null) {
129                 authBean.setSubject(subjectBean);
130             }
131             if (subjectLocalityIpAddress != null || subjectLocalityDnsAddress != null) {
132                 SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
133                 subjectLocality.setIpAddress(subjectLocalityIpAddress);
134                 subjectLocality.setDnsAddress(subjectLocalityDnsAddress);
135                 authBean.setSubjectLocality(subjectLocality);
136             }
137             authBean.setAuthenticationMethod("Password");
138             callback.setAuthenticationStatementData(Collections.singletonList(authBean));
139         } else if (statement == Statement.ATTR) {
140             AttributeStatementBean attrBean = new AttributeStatementBean();
141             AttributeBean attributeBean = new AttributeBean();
142             if (subjectBean != null) {
143                 attrBean.setSubject(subjectBean);
144                 attributeBean.setSimpleName("role");
145                 attributeBean.setQualifiedName("http://custom-ns");
146             } else {
147                 attributeBean.setQualifiedName("role");
148             }
149             if (customAttributeValues != null) {
150                 attributeBean.setCustomAttributeValues(customAttributeValues);   
151             } else {
152                 attributeBean.setAttributeValues(Collections.singletonList("user"));
153             }
154             attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
155             callback.setAttributeStatementData(Collections.singletonList(attrBean));
156         } else {
157             AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean();
158             if (subjectBean != null) {
159                 authzBean.setSubject(subjectBean);
160             }
161             ActionBean actionBean = new ActionBean();
162             actionBean.setContents("Read");
163             authzBean.setActions(Collections.singletonList(actionBean));
164             authzBean.setResource("endpoint");
165             authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT);
166             authzBean.setResource(resource);
167             callback.setAuthDecisionStatementData(Collections.singletonList(authzBean));
168         }
169     }
170     
171     protected KeyInfoBean createKeyInfo() throws Exception {
172         KeyInfoBean keyInfo = new KeyInfoBean();
173         if (statement == Statement.AUTHN) {
174             keyInfo.setCertificate(certs[0]);
175             keyInfo.setCertIdentifer(certIdentifier);
176         } else if (statement == Statement.ATTR) {
177             // Build a new Document
178             DocumentBuilderFactory docBuilderFactory = 
179                 DocumentBuilderFactory.newInstance();
180             docBuilderFactory.setNamespaceAware(true);
181             DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
182             Document doc = docBuilder.newDocument();
183                   
184             // Create an Encrypted Key
185             WSSecEncryptedKey encrKey = new WSSecEncryptedKey();
186             encrKey.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
187             encrKey.setUseThisCert(certs[0]);
188             encrKey.prepare(doc, null);
189             ephemeralKey = encrKey.getEphemeralKey();
190             Element encryptedKeyElement = encrKey.getEncryptedKeyElement();
191             
192             // Append the EncryptedKey to a KeyInfo element
193             Element keyInfoElement = 
194                 doc.createElementNS(
195                     WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
196                 );
197             keyInfoElement.setAttributeNS(
198                 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
199             );
200             keyInfoElement.appendChild(encryptedKeyElement);
201             
202             keyInfo.setElement(keyInfoElement);
203         }
204         return keyInfo;
205     }
206 }