Author: alessio.soldano(a)jboss.com
Date: 2011-05-26 08:16:19 -0400 (Thu, 26 May 2011)
New Revision: 14435
Added:
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingPolicyInterceptor.java
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreator.java
Modified:
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingInterceptor.java
Log:
[JBWS-3302] Adding UsernameToken processing interceptor for the policy-first scenario
Modified:
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingInterceptor.java
===================================================================
---
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingInterceptor.java 2011-05-26
11:02:48 UTC (rev 14434)
+++
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingInterceptor.java 2011-05-26
12:16:19 UTC (rev 14435)
@@ -21,25 +21,17 @@
*/
package org.jboss.wsf.stack.cxf.security.authentication;
-import java.security.Principal;
-import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
import org.apache.cxf.binding.soap.SoapMessage;
-import org.apache.cxf.common.security.SimplePrincipal;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.ws.security.wss4j.AbstractUsernameTokenAuthenticatingInterceptor;
-import org.jboss.logging.Logger;
-import org.jboss.security.auth.callback.CallbackHandlerPolicyContextHandler;
import org.jboss.wsf.spi.deployment.Endpoint;
import org.jboss.wsf.spi.security.SecurityDomainContext;
-import
org.jboss.wsf.stack.cxf.security.authentication.callback.UsernameTokenCallbackHandler;
import org.jboss.wsf.stack.cxf.security.nonce.NonceStore;
-import org.jboss.xb.binding.SimpleTypeBindings;
/**
* Interceptor which authenticates a current principal and populates Subject
@@ -50,19 +42,9 @@
*/
public class SubjectCreatingInterceptor extends
AbstractUsernameTokenAuthenticatingInterceptor
{
- private static final Logger log = Logger.getLogger(SubjectCreatingInterceptor.class);
-
- private static final int TIMESTAMP_FRESHNESS_THRESHOLD = 300;
-
- private boolean propagateContext;
-
- private int timestampThreshold = TIMESTAMP_FRESHNESS_THRESHOLD;
-
- private NonceStore nonceStore;
-
- private boolean decodeNonce = true;
-
private ThreadLocal<SecurityDomainContext> sdc = new
ThreadLocal<SecurityDomainContext>();
+
+ private SubjectCreator helper = new SubjectCreator();
public SubjectCreatingInterceptor()
{
@@ -94,99 +76,27 @@
@Override
public Subject createSubject(String name, String password, boolean isDigest, String
nonce, String created)
{
- if (isDigest)
- {
- verifyUsernameToken(nonce, created);
- // It is not possible at the moment to figure out if the digest has been created
- // using the original nonce bytes or the bytes of the (Base64)-encoded nonce,
some
- // legacy clients might use the (Base64)-encoded nonce bytes when creating a
digest;
- // lets default to true and assume the nonce has been Base-64 encoded, given
that
- // WSS4J client Base64-decodes the nonce before creating the digest
-
- CallbackHandler handler = new UsernameTokenCallbackHandler(nonce, created,
decodeNonce);
- CallbackHandlerPolicyContextHandler.setCallbackHandler(handler);
- }
-
- // authenticate and populate Subject
-
-
- Principal principal = new SimplePrincipal(name);
- Subject subject = new Subject();
-
- SecurityDomainContext ctx = sdc.get();
- boolean TRACE = log.isTraceEnabled();
- if (TRACE)
- log.trace("About to authenticate, using security domain '" +
ctx.getSecurityDomain() + "'");
-
- try
- {
- if (ctx.isValid(principal, password, subject) == false)
- {
- String msg = "Authentication failed, principal=" +
principal.getName();
- log.error(msg);
- throw new SecurityException(msg);
- }
- }
- finally
- {
- if (isDigest)
- {
- // does not remove the TL entry completely but limits the potential
- // growth to a number of available threads in a container
- CallbackHandlerPolicyContextHandler.setCallbackHandler(null);
- }
- }
-
- if (TRACE)
- log.trace("Authenticated, principal=" + name);
-
- if (propagateContext)
- {
- ctx.pushSubjectContext(subject, principal, password);
- if (TRACE)
- log.trace("Security Context has been propagated");
- }
- return subject;
+ return helper.createSubject(sdc.get(), name, password, isDigest, nonce, created);
}
- private void verifyUsernameToken(String nonce, String created)
- {
- if (created != null)
- {
- Calendar cal = SimpleTypeBindings.unmarshalDateTime(created);
- Calendar ref = Calendar.getInstance();
- ref.add(Calendar.SECOND, -timestampThreshold);
- if (ref.after(cal))
- throw new SecurityException("Request rejected since a stale timestamp
has been provided: " + created);
- }
-
- if (nonce != null && nonceStore != null)
- {
- if (nonceStore.hasNonce(nonce))
- throw new SecurityException(
- "Request rejected since a message with the same nonce has been
recently received; nonce = " + nonce);
- nonceStore.putNonce(nonce);
- }
- }
-
public void setPropagateContext(boolean propagateContext)
{
- this.propagateContext = propagateContext;
+ this.helper.setPropagateContext(propagateContext);
}
public void setTimestampThreshold(int timestampThreshold)
{
- this.timestampThreshold = timestampThreshold;
+ this.helper.setTimestampThreshold(timestampThreshold);
}
public void setNonceStore(NonceStore nonceStore)
{
- this.nonceStore = nonceStore;
+ this.helper.setNonceStore(nonceStore);
}
public void setDecodeNonce(boolean decodeNonce)
{
- this.decodeNonce = decodeNonce;
+ this.helper.setDecodeNonce(decodeNonce);
}
}
Added:
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingPolicyInterceptor.java
===================================================================
---
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingPolicyInterceptor.java
(rev 0)
+++
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreatingPolicyInterceptor.java 2011-05-26
12:16:19 UTC (rev 14435)
@@ -0,0 +1,97 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.wsf.stack.cxf.security.authentication;
+
+import javax.security.auth.Subject;
+
+import org.apache.cxf.common.security.UsernameToken;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.security.AbstractUsernameTokenInInterceptor;
+import org.apache.cxf.message.Message;
+import org.jboss.wsf.spi.deployment.Endpoint;
+import org.jboss.wsf.spi.security.SecurityDomainContext;
+import org.jboss.wsf.stack.cxf.security.nonce.NonceStore;
+
+/**
+ * Interceptor which authenticates a current principal and populates Subject
+ * To be used for policy-first scenarios
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @since 26-May-2011
+ */
+public class SubjectCreatingPolicyInterceptor extends AbstractUsernameTokenInInterceptor
+{
+ private ThreadLocal<SecurityDomainContext> sdc = new
ThreadLocal<SecurityDomainContext>();
+
+ private SubjectCreator helper = new SubjectCreator();
+
+ public SubjectCreatingPolicyInterceptor()
+ {
+ super();
+ helper.setPropagateContext(true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) throws Fault {
+ Endpoint ep = msg.getExchange().get(Endpoint.class);
+ sdc.set(ep.getSecurityDomainContext());
+ try
+ {
+ super.handleMessage(msg);
+ }
+ finally
+ {
+ if (sdc != null)
+ {
+ sdc.remove();
+ }
+ }
+ }
+
+ @Override
+ protected Subject createSubject(UsernameToken token)
+ {
+ return helper.createSubject(sdc.get(), token.getName(), token.getPassword(),
token.isHashed(), token.getNonce(),
+ token.getCreatedTime());
+ }
+
+ public void setPropagateContext(boolean propagateContext)
+ {
+ this.helper.setPropagateContext(propagateContext);
+ }
+
+ public void setTimestampThreshold(int timestampThreshold)
+ {
+ this.helper.setTimestampThreshold(timestampThreshold);
+ }
+
+ public void setNonceStore(NonceStore nonceStore)
+ {
+ this.helper.setNonceStore(nonceStore);
+ }
+
+ public void setDecodeNonce(boolean decodeNonce)
+ {
+ this.helper.setDecodeNonce(decodeNonce);
+ }
+
+}
Added:
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreator.java
===================================================================
---
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreator.java
(rev 0)
+++
stack/cxf/trunk/modules/server/src/main/java/org/jboss/wsf/stack/cxf/security/authentication/SubjectCreator.java 2011-05-26
12:16:19 UTC (rev 14435)
@@ -0,0 +1,156 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.wsf.stack.cxf.security.authentication;
+
+import java.security.Principal;
+import java.util.Calendar;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.cxf.common.security.SimplePrincipal;
+import org.jboss.logging.Logger;
+import org.jboss.security.auth.callback.CallbackHandlerPolicyContextHandler;
+import org.jboss.wsf.spi.security.SecurityDomainContext;
+import
org.jboss.wsf.stack.cxf.security.authentication.callback.UsernameTokenCallbackHandler;
+import org.jboss.wsf.stack.cxf.security.nonce.NonceStore;
+import org.jboss.xb.binding.SimpleTypeBindings;
+
+/**
+ * Creates Subject instances after having authenticated / authorized the provided
+ * user against the specified SecurityDomainContext.
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @author Sergey Beryozkin
+ *
+ */
+public class SubjectCreator
+{
+ private static final Logger log = Logger.getLogger(SubjectCreator.class);
+
+ private static final int TIMESTAMP_FRESHNESS_THRESHOLD = 300;
+
+ private boolean propagateContext;
+
+ private int timestampThreshold = TIMESTAMP_FRESHNESS_THRESHOLD;
+
+ private NonceStore nonceStore;
+
+ private boolean decodeNonce = true;
+
+ public Subject createSubject(SecurityDomainContext ctx, String name, String password,
boolean isDigest, String nonce, String created)
+ {
+ if (isDigest)
+ {
+ verifyUsernameToken(nonce, created);
+ // It is not possible at the moment to figure out if the digest has been created
+ // using the original nonce bytes or the bytes of the (Base64)-encoded nonce,
some
+ // legacy clients might use the (Base64)-encoded nonce bytes when creating a
digest;
+ // lets default to true and assume the nonce has been Base-64 encoded, given
that
+ // WSS4J client Base64-decodes the nonce before creating the digest
+
+ CallbackHandler handler = new UsernameTokenCallbackHandler(nonce, created,
decodeNonce);
+ CallbackHandlerPolicyContextHandler.setCallbackHandler(handler);
+ }
+
+ // authenticate and populate Subject
+
+
+ Principal principal = new SimplePrincipal(name);
+ Subject subject = new Subject();
+
+ boolean TRACE = log.isTraceEnabled();
+ if (TRACE)
+ log.trace("About to authenticate, using security domain '" +
ctx.getSecurityDomain() + "'");
+
+ try
+ {
+ if (ctx.isValid(principal, password, subject) == false)
+ {
+ String msg = "Authentication failed, principal=" +
principal.getName();
+ log.error(msg);
+ throw new SecurityException(msg);
+ }
+ }
+ finally
+ {
+ if (isDigest)
+ {
+ // does not remove the TL entry completely but limits the potential
+ // growth to a number of available threads in a container
+ CallbackHandlerPolicyContextHandler.setCallbackHandler(null);
+ }
+ }
+
+ if (TRACE)
+ log.trace("Authenticated, principal=" + name);
+
+ if (propagateContext)
+ {
+ ctx.pushSubjectContext(subject, principal, password);
+ if (TRACE)
+ log.trace("Security Context has been propagated");
+ }
+ return subject;
+ }
+
+ private void verifyUsernameToken(String nonce, String created)
+ {
+ if (created != null)
+ {
+ Calendar cal = SimpleTypeBindings.unmarshalDateTime(created);
+ Calendar ref = Calendar.getInstance();
+ ref.add(Calendar.SECOND, -timestampThreshold);
+ if (ref.after(cal))
+ throw new SecurityException("Request rejected since a stale timestamp
has been provided: " + created);
+ }
+
+ if (nonce != null && nonceStore != null)
+ {
+ if (nonceStore.hasNonce(nonce))
+ throw new SecurityException(
+ "Request rejected since a message with the same nonce has been
recently received; nonce = " + nonce);
+ nonceStore.putNonce(nonce);
+ }
+ }
+
+ public void setPropagateContext(boolean propagateContext)
+ {
+ this.propagateContext = propagateContext;
+ }
+
+ public void setTimestampThreshold(int timestampThreshold)
+ {
+ this.timestampThreshold = timestampThreshold;
+ }
+
+ public void setNonceStore(NonceStore nonceStore)
+ {
+ this.nonceStore = nonceStore;
+ }
+
+ public void setDecodeNonce(boolean decodeNonce)
+ {
+ this.decodeNonce = decodeNonce;
+ }
+
+}