Author: gertv
Date: Fri Apr 1 13:19:42 2011
New Revision: 1087697
URL: http://svn.apache.org/viewvc?rev=1087697&view=rev
Log:
SMX4NMR-265: Allow invoking an endpoint as the Subject passed along in the
Message
Added:
servicemix/smx4/nmr/trunk/nmr/core/src/test/java/org/apache/servicemix/nmr/core/ExchangeWithSecuritySubjectTest.java
Modified:
servicemix/smx4/nmr/trunk/nmr/api/src/main/java/org/apache/servicemix/nmr/api/Endpoint.java
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/ChannelImpl.java
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/EndpointRegistryImpl.java
Modified:
servicemix/smx4/nmr/trunk/nmr/api/src/main/java/org/apache/servicemix/nmr/api/Endpoint.java
URL:
http://svn.apache.org/viewvc/servicemix/smx4/nmr/trunk/nmr/api/src/main/java/org/apache/servicemix/nmr/api/Endpoint.java?rev=1087697&r1=1087696&r2=1087697&view=diff
==============================================================================
---
servicemix/smx4/nmr/trunk/nmr/api/src/main/java/org/apache/servicemix/nmr/api/Endpoint.java
(original)
+++
servicemix/smx4/nmr/trunk/nmr/api/src/main/java/org/apache/servicemix/nmr/api/Endpoint.java
Fri Apr 1 13:19:42 2011
@@ -72,6 +72,13 @@ public interface Endpoint {
String CHANNEL_SYNC_DELIVERY = "CHANNEL_SYNC_DELIVERY";
/**
+ * If this property is set to <code>true</code>, the endpoint code
+ * will be run as the <code>Subject</code> passed along with the message
+ * being sent to it.
+ */
+ String RUN_AS_SUBJECT = "RUN_AS_SUBJECT";
+
+ /**
* Set the channel so that the endpoint can send exchanges back
* when they are processed or act as a consumer itself.
* This method will be called by the NMR while the endpoint is registered.
Modified:
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/ChannelImpl.java
URL:
http://svn.apache.org/viewvc/servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/ChannelImpl.java?rev=1087697&r1=1087696&r2=1087697&view=diff
==============================================================================
---
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/ChannelImpl.java
(original)
+++
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/ChannelImpl.java
Fri Apr 1 13:19:42 2011
@@ -26,6 +26,9 @@ import org.apache.servicemix.nmr.api.int
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.security.auth.Subject;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
@@ -51,6 +54,7 @@ public class ChannelImpl implements Inte
private String name;
private AtomicBoolean closed = new AtomicBoolean();
private boolean shouldRunSynchronously;
+ private boolean runAsSubject;
public ChannelImpl(InternalEndpoint endpoint, Executor executor, NMR nmr) {
this.endpoint = endpoint;
@@ -74,6 +78,23 @@ public class ChannelImpl implements Inte
}
/**
+ * Will the endpoint code be invoked on behalf of the 'in' message subject?
+ */
+ public boolean isRunAsSubject() {
+ return runAsSubject;
+ }
+
+ /**
+ * Configure whether or not the endpoint will be invoked on behalf of the
subject
+ * found on the in message or not. Defaults to <code>false</code>.
+ *
+ * @param runAsSubject
+ */
+ public void setRunAsSubject(boolean runAsSubject) {
+ this.runAsSubject = runAsSubject;
+ }
+
+ /**
* Access to the bus
*
* @return the NMR
@@ -243,11 +264,16 @@ public class ChannelImpl implements Inte
// rather than delivering the exchange
// TODO:
// Process exchange
- endpoint.process(exchange);
+ Subject subject = exchange.getIn().getSecuritySubject();
+ if (isRunAsSubject() && subject != null) {
+ process(endpoint, exchange, subject);
+ } else {
+ endpoint.process(exchange);
+ }
} catch (RuntimeException e) {
handleFailure(exchange, e, false);
}
- }
+ }
/**
* Dispatch the exchange to the NMR
@@ -319,4 +345,24 @@ public class ChannelImpl implements Inte
protected final Executor getExecutor() {
return executor;
}
+
+ /**
+ * Make the endpoint process the exchange on behalf of the provided
security Subject.
+ *
+ * @param endpoint the target endpoint
+ * @param exchange the exchange to be processed
+ * @param subject the subject that the endpoint is to be invoked by
+ */
+ private void process(final InternalEndpoint endpoint, final
InternalExchange exchange, final Subject subject) {
+ try {
+ Subject.doAs(subject, new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ endpoint.process(exchange);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new NmrRuntimeException("Unable to invoke endpoint on behalf
of " + subject, e);
+ }
+ }
}
Modified:
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/EndpointRegistryImpl.java
URL:
http://svn.apache.org/viewvc/servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/EndpointRegistryImpl.java?rev=1087697&r1=1087696&r2=1087697&view=diff
==============================================================================
---
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/EndpointRegistryImpl.java
(original)
+++
servicemix/smx4/nmr/trunk/nmr/core/src/main/java/org/apache/servicemix/nmr/core/EndpointRegistryImpl.java
Fri Apr 1 13:19:42 2011
@@ -125,6 +125,7 @@ public class EndpointRegistryImpl implem
// Create channel
ChannelImpl channel = new ChannelImpl(wrapper, executor, nmr);
channel.setShouldRunSynchronously(isChannelSyncDelivery(properties));
+ channel.setRunAsSubject(isRunAsSubject(properties));
wrapper.setChannel(channel);
wrappers.put(wrapper, endpoint);
@@ -147,6 +148,13 @@ public class EndpointRegistryImpl implem
return getBoolean(properties.get(Endpoint.CHANNEL_SYNC_DELIVERY));
}
+ /*
+ * Should the Channel invoke the endpoint on behalf of the Subject in the
mesage?
+ */
+ private boolean isRunAsSubject(Map<String, ?> properties) {
+ return getBoolean(properties.get(Endpoint.RUN_AS_SUBJECT));
+ }
+
/**
* Unregister a previously register enpoint.
* In an OSGi world, this would be performed automatically by a
ServiceTracker.
Added:
servicemix/smx4/nmr/trunk/nmr/core/src/test/java/org/apache/servicemix/nmr/core/ExchangeWithSecuritySubjectTest.java
URL:
http://svn.apache.org/viewvc/servicemix/smx4/nmr/trunk/nmr/core/src/test/java/org/apache/servicemix/nmr/core/ExchangeWithSecuritySubjectTest.java?rev=1087697&view=auto
==============================================================================
---
servicemix/smx4/nmr/trunk/nmr/core/src/test/java/org/apache/servicemix/nmr/core/ExchangeWithSecuritySubjectTest.java
(added)
+++
servicemix/smx4/nmr/trunk/nmr/core/src/test/java/org/apache/servicemix/nmr/core/ExchangeWithSecuritySubjectTest.java
Fri Apr 1 13:19:42 2011
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.nmr.core;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.nmr.api.*;
+import org.apache.servicemix.nmr.api.event.ExchangeListener;
+import org.apache.servicemix.nmr.api.security.UserPrincipal;
+import org.apache.servicemix.nmr.api.service.ServiceHelper;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+
+import javax.security.auth.Subject;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.security.AccessController;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.*;
+
+/**
+ * Test class to ensure the NMR handles Exchange with a security subject set
on them correctly
+ */
+public class ExchangeWithSecuritySubjectTest extends TestCase {
+
+ private NMR nmr;
+
+ public void setUp() {
+ ServiceMix smx = new ServiceMix();
+ smx.init();
+ nmr = smx;
+ }
+
+ /**
+ * Ensure that endpoint code can be run as the passed in subject
+ */
+ public void testRunAsSubject() {
+ // let's register the endpoint first, asking for the code to invoked
on behalf of the subject
+ SubjectCapturingEndpoint endpoint = new SubjectCapturingEndpoint();
+ nmr.getEndpointRegistry().register(endpoint,
+
ServiceHelper.createMap(Endpoint.NAME, "runas",
+
Endpoint.RUN_AS_SUBJECT, "true"));
+
+
+ Subject subject = new Subject();
+ subject.getPrincipals().add(new UserPrincipal("VIP User"));
+
+ Channel channel = nmr.createChannel();
+ Exchange exchange = channel.createExchange(Pattern.InOnly);
+ exchange.setTarget(
+
nmr.getEndpointRegistry().lookup(ServiceHelper.createMap(Endpoint.NAME,
"runas")));
+ exchange.getIn().setSecuritySubject(subject);
+
+ channel.sendSync(exchange);
+
+ assertTrue("Endpoint should have been invoked 'as' the Subject",
+ endpoint.captures.contains(subject));
+ }
+
+ /**
+ * Ensure that endpoint code is not invoked on behalf of the Subject if
the option has not been
+ * explicitly enabled first.
+ */
+ public void testDoNotRunAsSubject() {
+ // let's register the endpoint first without asking for any special
Subject handling
+ SubjectCapturingEndpoint endpoint = new SubjectCapturingEndpoint();
+ nmr.getEndpointRegistry().register(endpoint,
+
ServiceHelper.createMap(Endpoint.NAME, "do_not_runas"));
+
+ Subject subject = new Subject();
+ subject.getPrincipals().add(new UserPrincipal("VIP User"));
+
+ Channel channel = nmr.createChannel();
+ Exchange exchange = channel.createExchange(Pattern.InOnly);
+ exchange.setTarget(
+
nmr.getEndpointRegistry().lookup(ServiceHelper.createMap(Endpoint.NAME,
"do_not_runas")));
+ exchange.getIn().setSecuritySubject(subject);
+
+ channel.sendSync(exchange);
+
+ assertTrue("Endpoint should not have been invoked 'as' the Subject",
+ endpoint.captures.isEmpty());
+ }
+
+ /*
+ * Endpoint that captures the Subject it is being invoked as.
+ */
+ private static class SubjectCapturingEndpoint implements Endpoint {
+
+ private Set<Subject> captures = new HashSet<Subject>();
+ private Channel channel;
+
+ public void process(Exchange exchange) {
+ Subject subject =
Subject.getSubject(AccessController.getContext());
+ if (subject != null) {
+ captures.add(subject);
+ }
+
+ exchange.setStatus(Status.Done);
+ channel.send(exchange);
+ }
+
+ public void setChannel(Channel channel) {
+ this.channel = channel;
+ }
+ }
+}