1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.saml;
21
22 import java.io.IOException;
23 import java.security.NoSuchProviderException;
24 import java.security.PublicKey;
25 import java.security.cert.X509Certificate;
26 import java.util.List;
27
28 import javax.security.auth.callback.CallbackHandler;
29 import javax.security.auth.callback.UnsupportedCallbackException;
30 import javax.xml.crypto.XMLStructure;
31 import javax.xml.crypto.dom.DOMStructure;
32 import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
33 import javax.xml.crypto.dsig.keyinfo.KeyValue;
34 import javax.xml.crypto.dsig.keyinfo.X509Data;
35 import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial;
36
37 import org.apache.wss4j.common.crypto.Crypto;
38 import org.apache.wss4j.common.crypto.CryptoType;
39 import org.apache.wss4j.common.ext.WSSecurityException;
40 import org.apache.wss4j.common.util.XMLUtils;
41 import org.opensaml.saml.saml2.core.SubjectConfirmationData;
42 import org.w3c.dom.Element;
43
44
45
46
47 public final class SAMLUtil {
48
49
50
51
52
53 private static final int MAX_KEYINFO_CONTENT_LIST_SIZE = 3;
54
55
56
57
58
59 private static final int MAX_X509DATA_SIZE = 5;
60
61 private static final String SIG_NS = "http://www.w3.org/2000/09/xmldsig#";
62
63 private SAMLUtil() {
64
65 }
66
67
68
69
70
71
72
73
74
75
76 public static SAMLKeyInfo getCredentialFromSubject(
77 SamlAssertionWrapper samlAssertion,
78 SAMLKeyInfoProcessor keyInfoProcessor,
79 Crypto sigCrypto
80 ) throws WSSecurityException {
81 if (samlAssertion.getSaml1() != null) {
82 return getCredentialFromSubject(
83 samlAssertion.getSaml1(), keyInfoProcessor, sigCrypto
84 );
85 } else if (samlAssertion.getSaml2() != null) {
86 return getCredentialFromSubject(
87 samlAssertion.getSaml2(), keyInfoProcessor, sigCrypto
88 );
89 }
90
91 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
92 new Object[] {"Cannot get credentials from an unknown SAML Assertion"});
93 }
94
95
96
97
98
99
100
101
102
103
104 public static SAMLKeyInfo getCredentialFromSubject(
105 org.opensaml.saml.saml1.core.Assertion assertion,
106 SAMLKeyInfoProcessor keyInfoProcessor,
107 Crypto sigCrypto
108 ) throws WSSecurityException {
109 for (org.opensaml.saml.saml1.core.Statement stmt : assertion.getStatements()) {
110 org.opensaml.saml.saml1.core.Subject samlSubject = null;
111 if (stmt instanceof org.opensaml.saml.saml1.core.AttributeStatement) {
112 org.opensaml.saml.saml1.core.AttributeStatement attrStmt =
113 (org.opensaml.saml.saml1.core.AttributeStatement) stmt;
114 samlSubject = attrStmt.getSubject();
115 } else if (stmt instanceof org.opensaml.saml.saml1.core.AuthenticationStatement) {
116 org.opensaml.saml.saml1.core.AuthenticationStatement authStmt =
117 (org.opensaml.saml.saml1.core.AuthenticationStatement) stmt;
118 samlSubject = authStmt.getSubject();
119 } else {
120 org.opensaml.saml.saml1.core.AuthorizationDecisionStatement authzStmt =
121 (org.opensaml.saml.saml1.core.AuthorizationDecisionStatement)stmt;
122 samlSubject = authzStmt.getSubject();
123 }
124
125 if (samlSubject != null && samlSubject.getSubjectConfirmation() != null) {
126 Element sub = samlSubject.getSubjectConfirmation().getDOM();
127 Element keyInfoElement =
128 XMLUtils.getDirectChildElement(sub, "KeyInfo", SIG_NS);
129 if (keyInfoElement != null) {
130 return getCredentialFromKeyInfo(
131 keyInfoElement, keyInfoProcessor, sigCrypto
132 );
133 }
134 }
135 }
136
137 return null;
138 }
139
140
141
142
143
144
145
146
147
148
149 public static SAMLKeyInfo getCredentialFromSubject(
150 org.opensaml.saml.saml2.core.Assertion assertion,
151 SAMLKeyInfoProcessor keyInfoProcessor,
152 Crypto sigCrypto
153 ) throws WSSecurityException {
154 org.opensaml.saml.saml2.core.Subject samlSubject = assertion.getSubject();
155 if (samlSubject != null) {
156 List<org.opensaml.saml.saml2.core.SubjectConfirmation> subjectConfList =
157 samlSubject.getSubjectConfirmations();
158 for (org.opensaml.saml.saml2.core.SubjectConfirmation subjectConfirmation : subjectConfList) {
159 SubjectConfirmationData subjConfData =
160 subjectConfirmation.getSubjectConfirmationData();
161 if (subjConfData != null) {
162 Element sub = subjConfData.getDOM();
163 Element keyInfoElement =
164 XMLUtils.getDirectChildElement(sub, "KeyInfo", SIG_NS);
165 if (keyInfoElement != null) {
166 return getCredentialFromKeyInfo(
167 keyInfoElement, keyInfoProcessor, sigCrypto
168 );
169 }
170 }
171 }
172 }
173
174 return null;
175 }
176
177
178
179
180
181
182
183
184
185
186 public static SAMLKeyInfo getCredentialFromKeyInfo(
187 Element keyInfoElement,
188 SAMLKeyInfoProcessor keyInfoProcessor,
189 Crypto sigCrypto
190 ) throws WSSecurityException {
191
192
193
194 if (keyInfoProcessor != null) {
195 SAMLKeyInfo samlKeyInfo = keyInfoProcessor.processSAMLKeyInfo(keyInfoElement);
196 if (samlKeyInfo != null) {
197 return samlKeyInfo;
198 }
199 }
200
201
202
203
204
205 KeyInfoFactory keyInfoFactory = null;
206 try {
207 keyInfoFactory = KeyInfoFactory.getInstance("DOM", "ApacheXMLDSig");
208 } catch (NoSuchProviderException ex) {
209 keyInfoFactory = KeyInfoFactory.getInstance("DOM");
210 }
211 XMLStructure keyInfoStructure = new DOMStructure(keyInfoElement);
212
213 try {
214 javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo =
215 keyInfoFactory.unmarshalKeyInfo(keyInfoStructure);
216 List<?> list = keyInfo.getContent();
217
218 X509Certificate[] certs = null;
219 PublicKey publicKey = null;
220 for (int i = 0; i < list.size(); i++) {
221
222 if (i >= MAX_KEYINFO_CONTENT_LIST_SIZE) {
223 break;
224 }
225 XMLStructure xmlStructure = (XMLStructure) list.get(i);
226 if (xmlStructure instanceof KeyValue && publicKey == null) {
227 publicKey = ((KeyValue)xmlStructure).getPublicKey();
228 } else if (xmlStructure instanceof X509Data) {
229 List<?> x509Data = ((X509Data)xmlStructure).getContent();
230 for (int j = 0; j < x509Data.size(); j++) {
231
232 if (j >= MAX_X509DATA_SIZE || certs != null) {
233 break;
234 }
235 Object x509obj = x509Data.get(j);
236 if (x509obj instanceof X509Certificate) {
237 certs = new X509Certificate[1];
238 certs[0] = (X509Certificate)x509obj;
239 } else if (x509obj instanceof X509IssuerSerial) {
240 if (sigCrypto == null) {
241 throw new WSSecurityException(
242 WSSecurityException.ErrorCode.FAILURE, "noSigCryptoFile"
243 );
244 }
245 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
246 cryptoType.setIssuerSerial(
247 ((X509IssuerSerial)x509obj).getIssuerName(),
248 ((X509IssuerSerial)x509obj).getSerialNumber()
249 );
250 certs = sigCrypto.getX509Certificates(cryptoType);
251 if (certs == null || certs.length < 1) {
252 throw new WSSecurityException(
253 WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity",
254 new Object[] {"cannot get certificate or key"}
255 );
256 }
257 }
258 }
259 }
260 }
261
262 if (certs != null || publicKey != null) {
263 SAMLKeyInfo samlKeyInfo = new SAMLKeyInfo(certs);
264 samlKeyInfo.setPublicKey(publicKey);
265 return samlKeyInfo;
266 }
267 } catch (Exception ex) {
268 throw new WSSecurityException(
269 WSSecurityException.ErrorCode.FAILURE, ex, "invalidSAMLsecurity",
270 new Object[] {"cannot get certificate or key"}
271 );
272 }
273 return null;
274 }
275
276 public static void doSAMLCallback(
277 CallbackHandler callbackHandler, SAMLCallback callback
278 ) {
279
280 try {
281
282 callbackHandler.handle(new SAMLCallback[]{callback});
283 } catch (IOException | UnsupportedCallbackException e) {
284 throw new IllegalStateException(
285 "Error while creating SAML assertion wrapper", e
286 );
287 }
288 }
289
290 }