001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.security.trust.impl;
038:
039: import java.net.URI;
040: import java.net.URISyntaxException;
041: import java.text.SimpleDateFormat;
042: import java.util.Calendar;
043: import java.util.Date;
044: import java.util.GregorianCalendar;
045: import java.util.List;
046: import java.util.Locale;
047: import java.util.Map;
048: import java.util.Set;
049: import java.util.UUID;
050: import java.security.cert.X509Certificate;
051:
052: import javax.xml.namespace.QName;
053:
054: import javax.security.auth.Subject;
055:
056: import com.sun.xml.ws.api.security.trust.Claims;
057: import com.sun.xml.ws.api.security.trust.STSAttributeProvider;
058: import com.sun.xml.ws.api.security.trust.STSAuthorizationProvider;
059: import com.sun.xml.ws.api.security.trust.WSTrustContract;
060: import com.sun.xml.ws.api.security.trust.WSTrustException;
061: import com.sun.xml.ws.api.security.trust.config.STSConfiguration;
062: import com.sun.xml.ws.api.security.trust.config.TrustSPMetadata;
063: import com.sun.xml.ws.policy.impl.bindings.AppliesTo;
064: import com.sun.xml.ws.security.IssuedTokenContext;
065: import com.sun.xml.ws.security.policy.SecureConversationToken;
066: import com.sun.xml.ws.security.trust.elements.str.KeyIdentifier;
067: import com.sun.xml.ws.security.trust.elements.str.SecurityTokenReference;
068: import com.sun.xml.ws.security.Token;
069: import com.sun.xml.ws.security.trust.Configuration;
070: import com.sun.xml.ws.security.trust.WSTrustConstants;
071: import com.sun.xml.ws.security.trust.WSTrustElementFactory;
072: import com.sun.xml.ws.security.trust.WSTrustFactory;
073: import com.sun.xml.ws.security.trust.elements.BinarySecret;
074: import com.sun.xml.ws.security.trust.elements.Entropy;
075: import com.sun.xml.ws.security.trust.elements.Lifetime;
076: import com.sun.xml.ws.security.trust.elements.RequestedProofToken;
077: import com.sun.xml.ws.security.trust.elements.RequestedAttachedReference;
078: import com.sun.xml.ws.security.trust.elements.RequestedUnattachedReference;
079: import com.sun.xml.ws.security.trust.elements.RequestSecurityToken;
080: import com.sun.xml.ws.security.trust.elements.RequestSecurityTokenResponse;
081: import com.sun.xml.ws.security.trust.elements.RequestSecurityTokenResponseCollection;
082: import com.sun.xml.ws.security.trust.elements.RequestedSecurityToken;
083: import com.sun.xml.ws.security.trust.util.WSTrustUtil;
084: import com.sun.xml.ws.security.wsu10.AttributedDateTime;
085: import com.sun.xml.wss.impl.MessageConstants;
086: import com.sun.xml.wss.impl.misc.SecurityUtil;
087:
088: import java.util.logging.Level;
089: import java.util.logging.Logger;
090: import com.sun.xml.ws.security.trust.logging.LogDomainConstants;
091:
092: import com.sun.xml.ws.security.trust.logging.LogStringsMessages;
093:
094: public abstract class IssueSamlTokenContract
095: implements
096: com.sun.xml.ws.api.security.trust.IssueSamlTokenContract<RequestSecurityToken, RequestSecurityTokenResponse> {
097:
098: private static final Logger log = Logger.getLogger(
099: LogDomainConstants.TRUST_IMPL_DOMAIN,
100: LogDomainConstants.TRUST_IMPL_DOMAIN_BUNDLE);
101:
102: protected STSConfiguration stsConfig;
103:
104: protected static final WSTrustElementFactory eleFac = WSTrustElementFactory
105: .newInstance();
106: protected static final SimpleDateFormat calendarFormatter = new SimpleDateFormat(
107: "yyyy-MM-dd'T'HH:mm:ss'.'sss'Z'", Locale.getDefault());
108:
109: private static final int DEFAULT_KEY_SIZE = 256;
110:
111: public void init(final STSConfiguration stsConfig) {
112: this .stsConfig = stsConfig;
113: }
114:
115: /** Issue a Token */
116: public RequestSecurityTokenResponse issue(
117: final RequestSecurityToken rst,
118: final IssuedTokenContext context) throws WSTrustException {
119: // Get AppliesTo
120: final AppliesTo applies = rst.getAppliesTo();
121: String appliesTo = null;
122: if (applies != null) {
123: appliesTo = WSTrustUtil.getAppliesToURI(applies);
124: }
125:
126: TrustSPMetadata spMd = stsConfig.getTrustSPMetadata(appliesTo);
127: if (spMd == null) {
128: // Only used for testing purpose; default should not documented
129: spMd = stsConfig.getTrustSPMetadata("default");
130: }
131: if (spMd == null) {
132: log.log(Level.SEVERE, LogStringsMessages
133: .WST_0004_UNKNOWN_SERVICEPROVIDER(appliesTo));
134: throw new WSTrustException(LogStringsMessages
135: .WST_0004_UNKNOWN_SERVICEPROVIDER(appliesTo));
136: }
137:
138: // Get TokenType
139: String tokenType = null;
140: final URI tokenTypeURI = rst.getTokenType();
141: if (tokenTypeURI != null) {
142: tokenType = tokenTypeURI.toString();
143: } else {
144: tokenType = spMd.getTokenType();
145: }
146: if (tokenType == null) {
147: tokenType = WSTrustConstants.SAML11_ASSERTION_TOKEN_TYPE;
148: }
149:
150: // Get KeyType
151: String keyType = null;
152: final URI keyTypeURI = rst.getKeyType();
153: if (keyTypeURI != null) {
154: keyType = keyTypeURI.toString();
155: } else {
156: keyType = spMd.getKeyType();
157: }
158: if (keyType == null) {
159: keyType = WSTrustConstants.SYMMETRIC_KEY;
160: }
161:
162: // Get authenticaed client Subject
163: final Subject subject = context.getRequestorSubject();
164: if (subject == null) {
165: log.log(Level.SEVERE, LogStringsMessages
166: .WST_0030_REQUESTOR_NULL());
167: throw new WSTrustException(LogStringsMessages
168: .WST_0030_REQUESTOR_NULL());
169: }
170:
171: // Check if the client is authorized to be issued the token
172: final STSAuthorizationProvider authzProvider = WSTrustFactory
173: .getSTSAuthorizationProvider();
174: if (!authzProvider.isAuthorized(subject, appliesTo, tokenType,
175: keyType)) {
176: String user = subject.getPrincipals().iterator().next()
177: .getName();
178: log.log(Level.SEVERE, LogStringsMessages
179: .WST_0015_CLIENT_NOT_AUTHORIZED(user, tokenType,
180: appliesTo));
181: throw new WSTrustException(LogStringsMessages
182: .WST_0015_CLIENT_NOT_AUTHORIZED(user, tokenType,
183: appliesTo));
184: }
185:
186: // Get claimed attributes
187: final Claims claims = rst.getClaims();
188: final STSAttributeProvider attrProvider = WSTrustFactory
189: .getSTSAttributeProvider();
190: final Map<QName, List<String>> claimedAttrs = attrProvider
191: .getClaimedAttributes(subject, appliesTo, tokenType,
192: claims);
193:
194: RequestedProofToken proofToken = null;
195: Entropy serverEntropy = null;
196: int keySize = 0;
197: if (WSTrustConstants.SYMMETRIC_KEY.equals(keyType)) {
198: //============================
199: // Create required secret key
200: //============================
201:
202: proofToken = eleFac.createRequestedProofToken();
203:
204: // Get client entropy
205: byte[] clientEntr = null;
206: final Entropy clientEntropy = rst.getEntropy();
207: if (clientEntropy != null) {
208: final BinarySecret clientBS = clientEntropy
209: .getBinarySecret();
210: if (clientBS == null) {
211: if (log.isLoggable(Level.FINE)) {
212: log.log(Level.FINE, LogStringsMessages
213: .WST_1009_NULL_BINARY_SECRET());
214: }
215: } else {
216: clientEntr = clientBS.getRawValue();
217: }
218: }
219:
220: keySize = (int) rst.getKeySize();
221: if (keySize < 1) {
222: keySize = DEFAULT_KEY_SIZE;
223: }
224: if (log.isLoggable(Level.FINE)) {
225: log.log(Level.FINE, LogStringsMessages
226: .WST_1010_KEY_SIZE(keySize, DEFAULT_KEY_SIZE));
227: }
228:
229: byte[] key = WSTrustUtil.generateRandomSecret(keySize / 8);
230: final BinarySecret serverBS = eleFac.createBinarySecret(
231: key, BinarySecret.NONCE_KEY_TYPE);
232: serverEntropy = eleFac.createEntropy(serverBS);
233: proofToken
234: .setProofTokenType(RequestedProofToken.COMPUTED_KEY_TYPE);
235:
236: // compute the secret key
237: try {
238: proofToken.setComputedKey(URI
239: .create(WSTrustConstants.CK_PSHA1));
240: key = SecurityUtil.P_SHA1(clientEntr, key, keySize / 8);
241: } catch (Exception ex) {
242: log.log(Level.SEVERE, LogStringsMessages
243: .WST_0013_ERROR_SECRET_KEY(
244: WSTrustConstants.CK_PSHA1, keySize,
245: appliesTo), ex);
246: throw new WSTrustException(LogStringsMessages
247: .WST_0013_ERROR_SECRET_KEY(
248: WSTrustConstants.CK_PSHA1, keySize,
249: appliesTo), ex);
250: }
251:
252: context.setProofKey(key);
253: } else if (WSTrustConstants.PUBLIC_KEY.equals(keyType)) {
254: final Set certs = context.getRequestorSubject()
255: .getPublicCredentials();
256: if (certs == null) {
257: log.log(Level.SEVERE, LogStringsMessages
258: .WST_0034_UNABLE_GET_CLIENT_CERT());
259: throw new WSTrustException(LogStringsMessages
260: .WST_0034_UNABLE_GET_CLIENT_CERT());
261: }
262: boolean addedClientCert = false;
263: for (Object o : certs) {
264: if (o instanceof X509Certificate) {
265: final X509Certificate clientCert = (X509Certificate) o;
266: context.setRequestorCertificate(clientCert);
267: addedClientCert = true;
268: }
269: }
270: if (!addedClientCert) {
271: log.log(Level.SEVERE, LogStringsMessages
272: .WST_0034_UNABLE_GET_CLIENT_CERT());
273: throw new WSTrustException(LogStringsMessages
274: .WST_0034_UNABLE_GET_CLIENT_CERT());
275: }
276: } else {
277: log.log(Level.SEVERE, LogStringsMessages
278: .WST_0025_INVALID_KEY_TYPE(keyType, appliesTo));
279: throw new WSTrustException(LogStringsMessages
280: .WST_0025_INVALID_KEY_TYPE(keyType, appliesTo));
281: }
282:
283: //==================
284: // Create the RSTR
285: //==================
286:
287: // get Context
288: URI ctx = null;
289: try {
290: final String rstCtx = rst.getContext();
291: if (rstCtx != null) {
292: ctx = new URI(rst.getContext());
293: }
294: } catch (URISyntaxException ex) {
295: log.log(Level.SEVERE, LogStringsMessages
296: .WST_0014_URI_SYNTAX(), ex);
297: throw new WSTrustException(LogStringsMessages
298: .WST_0014_URI_SYNTAX(), ex);
299: }
300:
301: // Create RequestedSecurityToken with SAML assertion
302: final String assertionId = "uuid-"
303: + UUID.randomUUID().toString();
304: final RequestedSecurityToken reqSecTok = eleFac
305: .createRequestedSecurityToken();
306: final Token samlToken = createSAMLAssertion(appliesTo,
307: tokenType, keyType, assertionId, stsConfig.getIssuer(),
308: claimedAttrs, context);
309: reqSecTok.setToken(samlToken);
310:
311: // Create RequestedAttachedReference and RequestedUnattachedReference
312: final SecurityTokenReference samlReference = createSecurityTokenReference(
313: assertionId, tokenType);
314: final RequestedAttachedReference raRef = eleFac
315: .createRequestedAttachedReference(samlReference);
316: final RequestedUnattachedReference ruRef = eleFac
317: .createRequestedUnattachedReference(samlReference);
318:
319: // Create Lifetime
320: final Lifetime lifetime = createLifetime();
321:
322: final RequestSecurityTokenResponse rstr = eleFac
323: .createRSTRForIssue(rst.getTokenType(), ctx, reqSecTok,
324: applies, raRef, ruRef, proofToken,
325: serverEntropy, lifetime);
326:
327: if (keySize > 0) {
328: rstr.setKeySize(keySize);
329: }
330:
331: //String issuer = config.getIssuer();
332:
333: // Token samlToken = createSAMLAssertion(appliesTo, tokenType, keyType, assertionId, issuer, claimedAttrs, context);
334: //rstr.getRequestedSecurityToken().setToken(samlToken);
335:
336: // Populate IssuedTokenContext
337: context.setSecurityToken(samlToken);
338: context.setAttachedSecurityTokenReference(samlReference);
339: context.setUnAttachedSecurityTokenReference(samlReference);
340: context.setCreationTime(new Date(currentTime));
341: context.setExpirationTime(new Date(currentTime
342: + stsConfig.getIssuedTokenTimeout()));
343:
344: return rstr;
345: }
346:
347: /** Issue a Collection of Token(s) possibly for different scopes */
348: public RequestSecurityTokenResponseCollection issueMultiple(
349: final RequestSecurityToken request,
350: final IssuedTokenContext context) throws WSTrustException {
351: throw new UnsupportedOperationException(
352: "Unsupported operation: issueMultiple");
353: }
354:
355: /** Renew a Token */
356: public RequestSecurityTokenResponse renew(
357: final RequestSecurityToken request,
358: final IssuedTokenContext context) throws WSTrustException {
359: throw new UnsupportedOperationException(
360: "Unsupported operation: renew");
361: }
362:
363: /** Cancel a Token */
364: public RequestSecurityTokenResponse cancel(
365: final RequestSecurityToken request,
366: final IssuedTokenContext context,
367: final Map issuedTokenCtxMap) throws WSTrustException {
368: throw new UnsupportedOperationException(
369: "Unsupported operation: cancel");
370: }
371:
372: /** Validate a Token */
373: public RequestSecurityTokenResponse validate(
374: final RequestSecurityToken request,
375: final IssuedTokenContext context) throws WSTrustException {
376: throw new UnsupportedOperationException(
377: "Unsupported operation: validate");
378: }
379:
380: /**
381: * handle an unsolicited RSTR like in the case of
382: * Client Initiated Secure Conversation.
383: */
384: public void handleUnsolicited(
385: final RequestSecurityTokenResponse rstr,
386: final IssuedTokenContext context) throws WSTrustException {
387: throw new UnsupportedOperationException(
388: "Unsupported operation: handleUnsolicited");
389: }
390:
391: public abstract Token createSAMLAssertion(String appliesTo,
392: String tokenType, String keyType, String assertionId,
393: String issuer, Map<QName, List<String>> claimedAttrs,
394: IssuedTokenContext context) throws WSTrustException;
395:
396: /*protected abstract boolean isAuthorized(Subject subject, String appliesTo, String tokenType, String keyType);
397:
398: protected abstract Map getClaimedAttributes(Subject subject, String appliesTo, String tokenType);
399:
400: protected byte[] createSecretKey(RequestSecurityToken rst)throws WSTrustException
401: {
402: // get key information
403: int keySize = (int)rst.getKeySize();
404: if (keySize < 1){
405: keySize = DEFAULT_KEY_SIZE;
406: }
407: URI keyType = rst.getKeyType();
408: URI alg = rst.getComputedKeyAlgorithm();
409:
410: Entropy entropy = rst.getEntropy();
411: BinarySecret bs = entropy.getBinarySecret();
412: byte[] nonce = bs.getRawValue();
413:
414: byte[] key = null;
415:
416: if (alg == null){
417: key = nonce;
418: } else if(alg.toString().equals(WSTrustConstants.CK_PSHA1)){
419: try {
420: key = SecurityUtil.P_SHA1(nonce,null, keySize/8 );
421: } catch (Exception ex) {
422: throw new WSTrustException(ex.getMessage(), ex);
423: }
424: } else {
425: throw new WSTrustException("Unsupported key computation algorithm: " + alg.toString());
426: }
427:
428: return key;
429: }*/
430:
431: private long currentTime;
432:
433: private Lifetime createLifetime() {
434: final Calendar cal = new GregorianCalendar();
435: int offset = cal.get(Calendar.ZONE_OFFSET);
436: if (cal.getTimeZone().inDaylightTime(cal.getTime())) {
437: offset += cal.getTimeZone().getDSTSavings();
438: }
439: synchronized (calendarFormatter) {
440: calendarFormatter.setTimeZone(cal.getTimeZone());
441:
442: // always send UTC/GMT time
443: final long beforeTime = cal.getTimeInMillis();
444: currentTime = beforeTime - offset;
445: cal.setTimeInMillis(currentTime);
446:
447: final AttributedDateTime created = new AttributedDateTime();
448: created.setValue(calendarFormatter.format(cal.getTime()));
449:
450: final AttributedDateTime expires = new AttributedDateTime();
451: cal.setTimeInMillis(currentTime
452: + stsConfig.getIssuedTokenTimeout());
453: expires.setValue(calendarFormatter.format(cal.getTime()));
454:
455: final Lifetime lifetime = eleFac.createLifetime(created,
456: expires);
457:
458: return lifetime;
459: }
460: }
461:
462: private SecurityTokenReference createSecurityTokenReference(
463: final String id, final String tokenType) {
464: String valueType = null;
465: if (WSTrustConstants.SAML10_ASSERTION_TOKEN_TYPE
466: .equals(tokenType)
467: || WSTrustConstants.SAML11_ASSERTION_TOKEN_TYPE
468: .equals(tokenType)) {
469: valueType = MessageConstants.WSSE_SAML_KEY_IDENTIFIER_VALUE_TYPE;
470: } else if (WSTrustConstants.SAML20_ASSERTION_TOKEN_TYPE
471: .equals(tokenType)) {
472: valueType = MessageConstants.WSSE_SAML_v2_0_KEY_IDENTIFIER_VALUE_TYPE;
473: }
474: final KeyIdentifier ref = eleFac.createKeyIdentifier(valueType,
475: null);
476: ref.setValue(id);
477: return eleFac.createSecurityTokenReference(ref);
478: }
479: }
|