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.secconv;
038:
039: import com.sun.xml.ws.api.security.trust.WSTrustException;
040: import com.sun.xml.ws.policy.AssertionSet;
041: import com.sun.xml.ws.policy.NestedPolicy;
042: import com.sun.xml.ws.policy.PolicyAssertion;
043: import com.sun.xml.ws.policy.impl.bindings.AppliesTo;
044: import com.sun.xml.ws.runtime.util.Session;
045: import com.sun.xml.ws.runtime.util.SessionManager;
046: import com.sun.xml.ws.security.IssuedTokenContext;
047: import com.sun.xml.ws.security.SecurityContextToken;
048: import com.sun.xml.ws.security.SecurityContextTokenInfo;
049: import com.sun.xml.ws.security.Token;
050: import com.sun.xml.ws.security.impl.policy.PolicyUtil;
051: import com.sun.xml.ws.security.impl.policy.Trust10;
052: import com.sun.xml.ws.security.policy.AlgorithmSuite;
053: import com.sun.xml.ws.security.policy.Constants;
054: import com.sun.xml.ws.security.policy.SymmetricBinding;
055: import com.sun.xml.ws.security.trust.impl.bindings.ObjectFactory;
056: import com.sun.xml.ws.security.trust.Configuration;
057: import com.sun.xml.ws.security.trust.WSTrustConstants;
058: import com.sun.xml.ws.security.trust.elements.BinarySecret;
059: import com.sun.xml.ws.security.trust.elements.CancelTarget;
060: import com.sun.xml.ws.security.trust.elements.Entropy;
061: import com.sun.xml.ws.security.trust.elements.Lifetime;
062: import com.sun.xml.ws.security.trust.elements.RequestedAttachedReference;
063: import com.sun.xml.ws.security.trust.elements.RequestedUnattachedReference;
064: import com.sun.xml.ws.security.trust.elements.RequestedProofToken;
065: import com.sun.xml.ws.security.trust.elements.RequestedSecurityToken;
066: import com.sun.xml.ws.security.trust.elements.RequestSecurityToken;
067: import com.sun.xml.ws.security.trust.elements.RequestSecurityTokenResponse;
068: import com.sun.xml.ws.security.trust.elements.RequestSecurityTokenResponseCollection;
069: import com.sun.xml.ws.security.trust.elements.str.Reference;
070: import com.sun.xml.ws.security.trust.elements.str.DirectReference;
071: import com.sun.xml.ws.security.trust.elements.str.SecurityTokenReference;
072: import com.sun.xml.ws.security.trust.impl.bindings.RequestSecurityTokenResponseType;
073: import com.sun.xml.ws.security.trust.util.WSTrustUtil;
074: import com.sun.xml.ws.security.wsu10.AttributedDateTime;
075: import com.sun.xml.ws.security.policy.SecureConversationToken;
076: import com.sun.xml.ws.security.secconv.impl.SecurityContextTokenInfoImpl;
077: import com.sun.xml.wss.impl.misc.SecurityUtil;
078:
079: import java.net.URI;
080: import java.net.URISyntaxException;
081: import java.text.SimpleDateFormat;
082: import java.util.Calendar;
083: import java.util.Date;
084: import java.util.GregorianCalendar;
085: import java.util.Locale;
086: import java.util.Map;
087: import java.util.Set;
088:
089: import java.util.logging.Level;
090: import java.util.logging.Logger;
091: import com.sun.xml.ws.security.secconv.logging.LogDomainConstants;
092: import com.sun.xml.ws.security.secconv.logging.LogStringsMessages;
093: import javax.xml.bind.JAXBElement;
094:
095: public class WSSCContract {
096:
097: private static final Logger log = Logger.getLogger(
098: LogDomainConstants.WSSC_IMPL_DOMAIN,
099: LogDomainConstants.WSSC_IMPL_DOMAIN_BUNDLE);
100:
101: //private Configuration config;
102:
103: private long currentTime;
104:
105: private static WSSCElementFactory eleFac = WSSCElementFactory
106: .newInstance();
107:
108: private static final int DEFAULT_KEY_SIZE = 128;
109:
110: // ToDo: Should read from the configuration
111: private static final long TIMEOUT = 36000000;
112: private static final SimpleDateFormat calendarFormatter = new SimpleDateFormat(
113: "yyyy-MM-dd'T'HH:mm:ss'.'sss'Z'", Locale.getDefault());
114:
115: public WSSCContract() {
116: //Empty default constructor
117: }
118:
119: public WSSCContract(Configuration config) {
120: init(config);
121: }
122:
123: public final void init(final Configuration config) {
124: //this.config = config;
125: }
126:
127: /** Issue a SecurityContextToken */
128: public RequestSecurityTokenResponse issue(
129: final RequestSecurityToken request,
130: final IssuedTokenContext context,
131: final SecureConversationToken scToken)
132: throws WSSecureConversationException {
133: // TokenType and context
134: URI tokenType = null;
135: URI con = null;
136: URI computeKeyAlgo = null;
137: tokenType = URI
138: .create(WSSCConstants.SECURITY_CONTEXT_TOKEN_TYPE);
139: final String conStr = request.getContext();
140: if (conStr != null) {
141: try {
142: con = new URI(conStr);
143: } catch (URISyntaxException ex) {
144: log.log(Level.SEVERE, LogStringsMessages
145: .WSSC_0008_URISYNTAX_EXCEPTION(request
146: .getContext()), ex);
147: throw new WSSecureConversationException(
148: LogStringsMessages
149: .WSSC_0008_URISYNTAX_EXCEPTION(request
150: .getContext()), ex);
151: }
152: }
153: computeKeyAlgo = URI.create(WSTrustConstants.CK_PSHA1);
154:
155: // AppliesTo
156: final AppliesTo scopes = request.getAppliesTo();
157:
158: final RequestedProofToken proofToken = eleFac
159: .createRequestedProofToken();
160:
161: // Get client entropy
162: byte[] clientEntr = null;
163: final Entropy clientEntropy = request.getEntropy();
164: if (clientEntropy != null) {
165: final BinarySecret clientBS = clientEntropy
166: .getBinarySecret();
167: if (clientBS == null) {
168: //ToDo
169: if (log.isLoggable(Level.FINE)) {
170: log.log(Level.FINE, LogStringsMessages
171: .WSSC_0009_CLIENT_ENTROPY_VALUE("null"));
172: }
173: } else {
174: clientEntr = clientBS.getRawValue();
175: if (log.isLoggable(Level.FINE)) {
176: log
177: .log(
178: Level.FINE,
179: LogStringsMessages
180: .WSSC_0009_CLIENT_ENTROPY_VALUE(clientEntropy
181: .toString()));
182: }
183: }
184: }
185: final RequestSecurityTokenResponse response = createRSTR(
186: computeKeyAlgo, scToken, request, scopes, clientEntr,
187: proofToken, tokenType, clientEntropy, context, con);
188:
189: if (log.isLoggable(Level.FINE)) {
190: log.log(Level.FINE, LogStringsMessages
191: .WSSC_0014_RSTR_RESPONSE(elemToString(response)));
192: }
193: return response;
194: }
195:
196: private RequestSecurityTokenResponse createRSTR(
197: final URI computeKeyAlgo,
198: final SecureConversationToken scToken,
199: final RequestSecurityToken request, final AppliesTo scopes,
200: final byte[] clientEntr,
201: final RequestedProofToken proofToken, final URI tokenType,
202: final Entropy clientEntropy,
203: final IssuedTokenContext context, final URI con)
204: throws WSSecureConversationException,
205: WSSecureConversationException {
206:
207: Trust10 trust10 = null;
208: SymmetricBinding symBinding = null;
209:
210: final NestedPolicy wsPolicy = scToken.getBootstrapPolicy();
211: final AssertionSet assertionSet = wsPolicy.getAssertionSet();
212: for (PolicyAssertion policyAssertion : assertionSet) {
213: if (PolicyUtil.isTrust10(policyAssertion)) {
214: trust10 = (Trust10) policyAssertion;
215: } else if (PolicyUtil.isSymmetricBinding(policyAssertion)) {
216: symBinding = (SymmetricBinding) policyAssertion;
217: }
218: }
219: boolean reqServerEntr = true;
220: boolean reqClientEntr = false;
221: if (trust10 != null) {
222: final Set trustReqdProps = trust10.getRequiredProperties();
223: reqServerEntr = trustReqdProps
224: .contains(Constants.REQUIRE_SERVER_ENTROPY);
225: reqClientEntr = trustReqdProps
226: .contains(Constants.REQUIRE_CLIENT_ENTROPY);
227: if (clientEntropy == null) {
228: if (reqClientEntr) {
229: log.log(Level.SEVERE, LogStringsMessages
230: .WSSC_0010_CLIENT_ENTROPY_CANNOT_NULL());
231: throw new WSSecureConversationException(
232: LogStringsMessages
233: .WSSC_0010_CLIENT_ENTROPY_CANNOT_NULL());
234: } else {
235: reqServerEntr = true;
236: }
237: }
238: }
239:
240: int keySize = (int) request.getKeySize();
241: if (keySize < 1 && symBinding != null) {
242: final AlgorithmSuite algoSuite = symBinding
243: .getAlgorithmSuite();
244: keySize = algoSuite.getMinSKLAlgorithm();
245: }
246: if (keySize < 1) {
247: keySize = DEFAULT_KEY_SIZE;
248: }
249: if (log.isLoggable(Level.FINE)) {
250: log.log(Level.FINE, LogStringsMessages
251: .WSSC_0011_KEY_SIZE_VALUE(keySize,
252: this .DEFAULT_KEY_SIZE));
253: }
254:
255: byte[] secret = WSTrustUtil.generateRandomSecret(keySize / 8);
256: final String proofTokenType = (clientEntr == null || clientEntr.length == 0) ? BinarySecret.SYMMETRIC_KEY_TYPE
257: : BinarySecret.NONCE_KEY_TYPE;
258: Entropy serverEntropy = null;
259: if (reqServerEntr) {
260: final BinarySecret serverBS = eleFac.createBinarySecret(
261: secret, proofTokenType);
262: if (proofTokenType.equals(BinarySecret.NONCE_KEY_TYPE)) {
263: serverEntropy = eleFac.createEntropy(serverBS);
264: proofToken
265: .setProofTokenType(RequestedProofToken.COMPUTED_KEY_TYPE);
266: proofToken.setComputedKey(computeKeyAlgo);
267:
268: // compute the secret key
269: try {
270: secret = SecurityUtil.P_SHA1(clientEntr, secret,
271: keySize / 8);
272: } catch (Exception ex) {
273: log.log(Level.SEVERE, LogStringsMessages
274: .WSSC_0012_COMPUTE_SECKEY(), ex);
275: throw new WSSecureConversationException(
276: LogStringsMessages
277: .WSSC_0012_COMPUTE_SECKEY(), ex);
278: }
279:
280: } else {
281: proofToken
282: .setProofTokenType(RequestedProofToken.BINARY_SECRET_TYPE);
283: proofToken.setBinarySecret(serverBS);
284: }
285: } else if (clientEntropy != null) {
286: secret = clientEntr;
287: proofToken
288: .setProofTokenType(RequestedProofToken.BINARY_SECRET_TYPE);
289: proofToken.setBinarySecret(clientEntropy.getBinarySecret());
290: }
291:
292: return createResponse(serverEntropy, con, scopes, secret,
293: proofToken, context, tokenType);
294: }
295:
296: private RequestSecurityTokenResponse createResponse(
297: final Entropy serverEntropy, final URI con,
298: final AppliesTo scopes, final byte[] secret,
299: final RequestedProofToken proofToken,
300: final IssuedTokenContext context, final URI tokenType)
301: throws WSSecureConversationException {
302:
303: // Create Security Context and SecurityContextToken
304: final SecurityContextToken token = WSTrustUtil
305: .createSecurityContextToken(eleFac);
306: final RequestedSecurityToken rst = eleFac
307: .createRequestedSecurityToken(token);
308:
309: // Create references
310: final SecurityTokenReference attachedReference = createSecurityTokenReference(
311: token.getWsuId(), false);
312: final RequestedAttachedReference rar = eleFac
313: .createRequestedAttachedReference(attachedReference);
314: final SecurityTokenReference unattachedRef = createSecurityTokenReference(
315: token.getIdentifier().toString(), true);
316: final RequestedUnattachedReference rur = eleFac
317: .createRequestedUnattachedReference(unattachedRef);
318:
319: // Create Lifetime
320: final Lifetime lifetime = createLifetime();
321:
322: RequestSecurityTokenResponse response = null;
323: try {
324: response = eleFac.createRSTRForIssue(tokenType, con, rst,
325: scopes, rar, rur, proofToken, serverEntropy,
326: lifetime);
327: } catch (WSTrustException ex) {
328: log.log(Level.SEVERE, LogStringsMessages
329: .WSSC_0020_PROBLEM_CREATING_RSTR(), ex);
330: throw new WSSecureConversationException(LogStringsMessages
331: .WSSC_0020_PROBLEM_CREATING_RSTR(), ex);
332: }
333:
334: final Session session = SessionManager.getSessionManager()
335: .createSession(token.getIdentifier().toString());
336: if (log.isLoggable(Level.FINE)) {
337: log.log(Level.FINE, LogStringsMessages
338: .WSSC_1010_CREATING_SESSION(token.getIdentifier()));
339: }
340: populateITC(session, secret, token, attachedReference, context,
341: unattachedRef);
342: return response;
343: }
344:
345: private void populateITC(final Session session,
346: final byte[] secret, final SecurityContextToken token,
347: final SecurityTokenReference attachedReference,
348: final IssuedTokenContext context,
349: final SecurityTokenReference unattachedRef) {
350:
351: // Populate the IssuedTokenContext
352: context.setSecurityToken(token);
353: context.setAttachedSecurityTokenReference(attachedReference);
354: context.setUnAttachedSecurityTokenReference(unattachedRef);
355: context.setProofKey(secret);
356: context.setCreationTime(new Date(currentTime));
357: context.setExpirationTime(new Date(currentTime + TIMEOUT));
358:
359: final SecurityContextTokenInfo sctinfo = new SecurityContextTokenInfoImpl();
360: sctinfo.setIdentifier(token.getIdentifier().toString());
361: sctinfo.setExternalId(token.getWsuId());
362: sctinfo.addInstance(null, secret);
363:
364: sctinfo.setCreationTime(new Date(currentTime));
365: sctinfo.setExpirationTime(new Date(currentTime + TIMEOUT));
366:
367: session.setSecurityInfo(sctinfo);
368: }
369:
370: /** Issue a Collection of Token(s) possibly for different scopes */
371: public RequestSecurityTokenResponseCollection issueMultiple(
372: final RequestSecurityToken request,
373: final IssuedTokenContext context)
374: throws WSSecureConversationException {
375: return null;
376: }
377:
378: /** Renew a SecurityContextToken */
379: public RequestSecurityTokenResponse renew(
380: final RequestSecurityToken request,
381: final IssuedTokenContext context)
382: throws WSSecureConversationException {
383: return null;
384: }
385:
386: /** Cancel a SecurityContextToken */
387: public RequestSecurityTokenResponse cancel(
388: final RequestSecurityToken request,
389: final IssuedTokenContext context, final Map issuedTokCtxMap)
390: throws WSSecureConversationException {
391: final CancelTarget cancelTgt = request.getCancelTarget();
392: final SecurityTokenReference str = cancelTgt
393: .getSecurityTokenReference();
394: String id = null;
395: final Reference ref = str.getReference();
396: if (ref.getType().equals("Reference")) {
397: id = ((DirectReference) ref).getURIAttr().toString();
398: }
399:
400: final IssuedTokenContext cxt = (IssuedTokenContext) issuedTokCtxMap
401: .get(id);
402: if (cxt == null || cxt.getSecurityToken() == null) {
403: log.log(Level.SEVERE, LogStringsMessages
404: .WSSC_0015_UNKNOWN_CONTEXT(id));
405: throw new WSSecureConversationException(LogStringsMessages
406: .WSSC_0015_UNKNOWN_CONTEXT(id));
407: }
408:
409: final RequestSecurityTokenResponse rstr = eleFac
410: .createRSTRForCancel();
411: if (log.isLoggable(Level.FINE)) {
412: log.log(Level.FINE, LogStringsMessages
413: .WSSC_0014_RSTR_RESPONSE(elemToString(rstr)));
414: }
415: return rstr;
416: }
417:
418: /** Validate a SecurityContextToken */
419: public RequestSecurityTokenResponse validate(
420: final RequestSecurityToken request,
421: final IssuedTokenContext context)
422: throws WSSecureConversationException {
423: return null;
424: }
425:
426: /**
427: * handle an unsolicited RSTR like in the case of
428: * Client Initiated Secure Conversation.
429: */
430: public void handleUnsolicited(
431: final RequestSecurityTokenResponse rstr,
432: final IssuedTokenContext context)
433: throws WSSecureConversationException {
434: //final AppliesTo scope = rstr.getAppliesTo();
435: final RequestedSecurityToken rqSecToken = rstr
436: .getRequestedSecurityToken();
437: final Token token = rqSecToken.getToken();
438: final RequestedProofToken rqProofToken = rstr
439: .getRequestedProofToken();
440: final String proofTokenType = rqProofToken.getProofTokenType();
441: if (proofTokenType
442: .equals(RequestedProofToken.BINARY_SECRET_TYPE)) {
443: final BinarySecret binarySecret = rqProofToken
444: .getBinarySecret();
445: if (binarySecret.getType().equals(
446: BinarySecret.SYMMETRIC_KEY_TYPE)) {
447: final byte[] secret = binarySecret.getRawValue();
448: context.setProofKey(secret);
449: }
450: } else if (proofTokenType
451: .equals(RequestedProofToken.ENCRYPTED_KEY_TYPE)) {
452: //ToDo
453: }
454:
455: context.setSecurityToken(token);
456: final long curTime = System.currentTimeMillis();
457: final Date creationTime = new Date(curTime);
458: final Date expirationTime = new Date(curTime + TIMEOUT);
459: context.setCreationTime(creationTime);
460: context.setExpirationTime(expirationTime);
461: if (log.isLoggable(Level.FINER)) {
462: log.log(Level.FINER, LogStringsMessages
463: .WSSC_1003_SETTING_TIMES(creationTime.toString(),
464: expirationTime.toString()));
465: }
466: }
467:
468: private SecurityTokenReference createSecurityTokenReference(
469: final String id, final boolean unattached) {
470: final String uri = (unattached ? id : "#" + id);
471: final Reference ref = eleFac.createDirectReference(
472: WSSCConstants.SECURITY_CONTEXT_TOKEN_TYPE, uri);
473: return eleFac.createSecurityTokenReference(ref);
474: }
475:
476: private Lifetime createLifetime() {
477: final Calendar cal = new GregorianCalendar();
478: int offset = cal.get(Calendar.ZONE_OFFSET);
479: if (cal.getTimeZone().inDaylightTime(cal.getTime())) {
480: offset += cal.getTimeZone().getDSTSavings();
481: }
482: synchronized (calendarFormatter) {
483: calendarFormatter.setTimeZone(cal.getTimeZone());
484:
485: // always send UTC/GMT time
486: final long beforeTime = cal.getTimeInMillis();
487: currentTime = beforeTime - offset;
488: cal.setTimeInMillis(currentTime);
489:
490: final AttributedDateTime created = new AttributedDateTime();
491: created.setValue(calendarFormatter.format(cal.getTime()));
492:
493: final AttributedDateTime expires = new AttributedDateTime();
494: cal.setTimeInMillis(currentTime + TIMEOUT);
495: expires.setValue(calendarFormatter.format(cal.getTime()));
496:
497: final Lifetime lifetime = eleFac.createLifetime(created,
498: expires);
499:
500: return lifetime;
501: }
502: }
503:
504: private String elemToString(final RequestSecurityTokenResponse rstr) {
505: try {
506: final javax.xml.bind.Marshaller marshaller = eleFac
507: .getContext().createMarshaller();
508: final JAXBElement<RequestSecurityTokenResponseType> rstrElement = (new ObjectFactory())
509: .createRequestSecurityTokenResponse((RequestSecurityTokenResponseType) rstr);
510: marshaller.setProperty(
511: javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT,
512: Boolean.TRUE);
513: final java.io.StringWriter writer = new java.io.StringWriter();
514: marshaller.marshal(rstrElement, writer);
515: return writer.toString();
516: } catch (Exception e) {
517: log.log(Level.SEVERE, LogStringsMessages
518: .WSSC_0001_ERROR_MARSHAL_LOG());
519: throw new RuntimeException(LogStringsMessages
520: .WSSC_0001_ERROR_MARSHAL_LOG(), e);
521: }
522: }
523:
524: }
|