You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by lq...@apache.org on 2016/02/24 13:00:42 UTC

svn commit: r1732094 - in /qpid/java/trunk: broker-core/ broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/ broker-core/src/test/resources/ssl/ broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/p...

Author: lquack
Date: Wed Feb 24 12:00:42 2016
New Revision: 1732094

URL: http://svn.apache.org/viewvc?rev=1732094&view=rev
Log:
QPID-7094: [Java Broker] Add OAuth2 unit tests

Added:
    qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java
    qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpoint.java
    qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpointHolder.java
    qpid/java/trunk/broker-core/src/test/resources/ssl/
    qpid/java/trunk/broker-core/src/test/resources/ssl/test_keystore.jks
    qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/
    qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticatorTest.java
    qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2PreemptiveAuthenticatorTest.java
Modified:
    qpid/java/trunk/broker-core/pom.xml
    qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticator.java

Modified: qpid/java/trunk/broker-core/pom.xml
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/pom.xml?rev=1732094&r1=1732093&r2=1732094&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/pom.xml (original)
+++ qpid/java/trunk/broker-core/pom.xml Wed Feb 24 12:00:42 2016
@@ -97,6 +97,33 @@
       <scope>test</scope>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-servlet_3.0_spec</artifactId>
+      <version>${geronimo-servlet-version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${jetty-version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.eclipse.jetty.orbit</groupId>
+          <artifactId>javax.servlet</artifactId>
+        </exclusion>
+      </exclusions>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${jetty-version}</version>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
    
   <build>

Added: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java?rev=1732094&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java (added)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java Wed Feb 24 12:00:42 2016
@@ -0,0 +1,317 @@
+/*
+ *
+ * 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.qpid.server.security.auth.manager.oauth2;
+
+import static org.mockito.Mockito.when;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.oauth2.cloudfoundry.CloudFoundryOAuth2IdentityResolverService;
+import org.apache.qpid.server.util.BrokerTestHelper;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class OAuth2AuthenticationProviderImplTest extends QpidTestCase
+{
+    static final String UTF8 = StandardCharsets.UTF_8.name();
+
+    private static final String TEST_ENDPOINT_HOST = "localhost";
+    static final int TEST_ENDPOINT_PORT = 38888;
+    private static final String TEST_AUTHORIZATION_ENDPOINT_PATH = "/testauth";
+    private static final String TEST_TOKEN_ENDPOINT_PATH = "/testtoken";
+    private static final String TEST_IDENTITY_RESOLVER_ENDPOINT_PATH = "/testidresolver";
+    private static final String TEST_POST_LOGOUT_PATH = "/testpostlogout";
+
+    static final String TEST_CLIENT_ID = "testClientId";
+    static final String TEST_CLIENT_SECRET = "testClientSecret";
+    private static final String TEST_IDENTITY_RESOLVER_TYPE = CloudFoundryOAuth2IdentityResolverService.TYPE;
+    private static final String TEST_AUTHORIZATION_ENDPOINT_URI = String.format("https://%s:%d%s", TEST_ENDPOINT_HOST, TEST_ENDPOINT_PORT, TEST_AUTHORIZATION_ENDPOINT_PATH);
+    private static final String TEST_TOKEN_ENDPOINT_URI = String.format("https://%s:%d%s", TEST_ENDPOINT_HOST, TEST_ENDPOINT_PORT, TEST_TOKEN_ENDPOINT_PATH);
+    private static final String TEST_AUTHORIZATION_ENDPOINT_NEEDS_AUTH = "true";
+    private static final String TEST_IDENTITY_RESOLVER_ENDPOINT_URI = String.format("https://%s:%d%s", TEST_ENDPOINT_HOST, TEST_ENDPOINT_PORT, TEST_IDENTITY_RESOLVER_ENDPOINT_PATH);
+    private static final String TEST_POST_LOGOUT_URI = String.format("https://%s:%d%s", TEST_ENDPOINT_HOST, TEST_ENDPOINT_PORT, TEST_POST_LOGOUT_PATH);
+    private static final String TEST_SCOPE = "testScope";
+    private static final String TEST_TRUST_STORE_NAME = null;
+
+    private static final String TEST_VALID_AUTHORIZATION_CODE = "validAuthorizationCode";
+    private static final String TEST_INVALID_AUTHORIZATION_CODE = "invalidAuthorizationCode";
+    private static final String TEST_VALID_ACCESS_TOKEN = "validAccessToken";
+    private static final String TEST_INVALID_ACCESS_TOKEN = "invalidAccessToken";
+    private static final String TEST_USER_NAME = "testUser";
+
+
+    private static final String TEST_REDIRECT_URI = "localhost:23523";
+
+    private OAuth2AuthenticationProvider<?> _authProvider;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        Broker broker = BrokerTestHelper.createBrokerMock();
+        TaskExecutor taskExecutor = CurrentThreadTaskExecutor.newStartedInstance();
+        when(broker.getTaskExecutor()).thenReturn(taskExecutor);
+        when(broker.getChildExecutor()).thenReturn(taskExecutor);
+        final Map<String, Object> authProviderAttributes = new HashMap<>();
+        authProviderAttributes.put(ConfiguredObject.NAME, "testOAuthProvider");
+        authProviderAttributes.put("clientId", TEST_CLIENT_ID);
+        authProviderAttributes.put("clientSecret", TEST_CLIENT_SECRET);
+        authProviderAttributes.put("identityResolverType", TEST_IDENTITY_RESOLVER_TYPE);
+        authProviderAttributes.put("authorizationEndpointURI", TEST_AUTHORIZATION_ENDPOINT_URI);
+        authProviderAttributes.put("tokenEndpointURI", TEST_TOKEN_ENDPOINT_URI);
+        authProviderAttributes.put("tokenEndpointNeedsAuth", TEST_AUTHORIZATION_ENDPOINT_NEEDS_AUTH);
+        authProviderAttributes.put("identityResolverEndpointURI", TEST_IDENTITY_RESOLVER_ENDPOINT_URI);
+        authProviderAttributes.put("postLogoutURI", TEST_POST_LOGOUT_URI);
+        authProviderAttributes.put("scope", TEST_SCOPE);
+        authProviderAttributes.put("trustStore", TEST_TRUST_STORE_NAME);
+
+        _authProvider = new OAuth2AuthenticationProviderImpl(authProviderAttributes, broker);
+        _authProvider.open();
+        assertEquals("Could not successfully open authProvider", State.ACTIVE, _authProvider.getState());
+
+        final TrustManager[] trustingTrustManager = new TrustManager[] {new TrustingTrustManager() };
+
+        final SSLContext sc = SSLContext.getInstance("SSL");
+        sc.init(null, trustingTrustManager, new java.security.SecureRandom());
+        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+        HttpsURLConnection.setDefaultHostnameVerifier(new BlindHostnameVerifier());
+    }
+
+    public void testGetSecureOnlyMechanisms() throws Exception
+    {
+        assertEquals("OAuth2 should be a secure only mechanism",
+                     Collections.singletonList(OAuth2SaslServer.MECHANISM), _authProvider.getSecureOnlyMechanisms());
+    }
+
+    public void testAuthenticateViaSasl() throws Exception
+    {
+        OAuth2MockEndpointHolder
+                server = new OAuth2MockEndpointHolder(Collections.singletonMap(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH,
+                                                                               createMockIdentityResolverEndpoint()));
+        try
+        {
+            server.start();
+            SaslServer saslServer = _authProvider.createSaslServer(OAuth2SaslServer.MECHANISM, TEST_ENDPOINT_HOST, null);
+            AuthenticationResult authenticationResult = _authProvider.authenticate(saslServer, ("auth=Bearer "
+                                                                                                + TEST_VALID_ACCESS_TOKEN
+                                                                                                + "\1\1").getBytes(UTF8));
+            assertSuccess(authenticationResult);
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    public void testFailAuthenticateViaSasl() throws Exception
+    {
+        OAuth2MockEndpoint mockIdentityResolverEndpoint = createMockIdentityResolverEndpoint();
+        mockIdentityResolverEndpoint.putExpectedParameter("token", TEST_INVALID_ACCESS_TOKEN);
+        mockIdentityResolverEndpoint.setResponse(400, "{\"error\":\"invalid_token\"}");
+        OAuth2MockEndpointHolder
+                server = new OAuth2MockEndpointHolder(Collections.singletonMap(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH,
+                                                                               mockIdentityResolverEndpoint));
+        try
+        {
+            server.start();
+            SaslServer saslServer = _authProvider.createSaslServer(OAuth2SaslServer.MECHANISM, TEST_ENDPOINT_HOST, null);
+            AuthenticationResult authenticationResult = _authProvider.authenticate(saslServer, ("auth=Bearer "
+                                                                                                + TEST_INVALID_ACCESS_TOKEN
+                                                                                                + "\1\1").getBytes(UTF8));
+            assertFailure(authenticationResult, "invalid_token");
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    public void testAuthenticateViaAuthorizationCode() throws Exception
+    {
+        Map<String, OAuth2MockEndpoint> mockEndpoints = new HashMap<>();
+        mockEndpoints.put(TEST_TOKEN_ENDPOINT_PATH, createMockTokenEndpoint());
+        mockEndpoints.put(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH, createMockIdentityResolverEndpoint());
+        OAuth2MockEndpointHolder server = new OAuth2MockEndpointHolder(mockEndpoints);
+        try
+        {
+            server.start();
+            AuthenticationResult authenticationResult =
+                    _authProvider.authenticateViaAuthorizationCode(TEST_VALID_AUTHORIZATION_CODE, TEST_REDIRECT_URI);
+            assertSuccess(authenticationResult);
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    public void testFailAuthenticateViaInvalidAuthorizationCode() throws Exception
+    {
+        Map<String, OAuth2MockEndpoint> mockEndpoints = new HashMap<>();
+        final OAuth2MockEndpoint mockTokenEndpoint = createMockTokenEndpoint();
+        mockTokenEndpoint.putExpectedParameter("code", TEST_INVALID_AUTHORIZATION_CODE);
+        mockTokenEndpoint.setResponse(400, "{\"error\":\"invalid_grant\",\"error_description\":\"authorization grant is not valid\"}");
+        mockEndpoints.put(TEST_TOKEN_ENDPOINT_PATH, mockTokenEndpoint);
+        mockEndpoints.put(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH, createMockIdentityResolverEndpoint());
+        OAuth2MockEndpointHolder server = new OAuth2MockEndpointHolder(mockEndpoints);
+        try
+        {
+            server.start();
+            AuthenticationResult authenticationResult =
+                    _authProvider.authenticateViaAuthorizationCode(TEST_INVALID_AUTHORIZATION_CODE, TEST_REDIRECT_URI);
+            assertFailure(authenticationResult, "invalid_grant");
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    public void testAuthenticateViaAccessToken() throws Exception
+    {
+        OAuth2MockEndpointHolder
+                server = new OAuth2MockEndpointHolder(Collections.singletonMap(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH,
+                                                                               createMockIdentityResolverEndpoint()));
+        try
+        {
+            server.start();
+            AuthenticationResult authenticationResult = _authProvider.authenticateViaAccessToken(TEST_VALID_ACCESS_TOKEN);
+            assertSuccess(authenticationResult);
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    public void testFailAuthenticateViaInvalidAccessToken() throws Exception
+    {
+        OAuth2MockEndpoint mockIdentityResolverEndpoint = createMockIdentityResolverEndpoint();
+        mockIdentityResolverEndpoint.putExpectedParameter("token", TEST_INVALID_ACCESS_TOKEN);
+        mockIdentityResolverEndpoint.setResponse(400, "{\"error\":\"invalid_token\"}");
+        OAuth2MockEndpointHolder
+                server = new OAuth2MockEndpointHolder(Collections.singletonMap(TEST_IDENTITY_RESOLVER_ENDPOINT_PATH,
+                                                                               mockIdentityResolverEndpoint));
+        try
+        {
+            server.start();
+            AuthenticationResult authenticationResult =
+                    _authProvider.authenticateViaAccessToken(TEST_INVALID_ACCESS_TOKEN);
+            assertFailure(authenticationResult, "invalid_token");
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    private void assertSuccess(final AuthenticationResult authenticationResult)
+    {
+        assertEquals("Authentication was not successful: " + authenticationResult.getCause(),
+                     AuthenticationResult.AuthenticationStatus.SUCCESS, authenticationResult.getStatus());
+        assertEquals("AuthenticationResult has the wrong Principal",
+                     TEST_USER_NAME, authenticationResult.getMainPrincipal().getName());
+    }
+
+    private void assertFailure(final AuthenticationResult authenticationResult, final String failureCauseString)
+    {
+        assertEquals("Authentication should not succeed",
+                     AuthenticationResult.AuthenticationStatus.ERROR, authenticationResult.getStatus());
+        assertTrue(authenticationResult.getCause().toString(), authenticationResult.getCause().toString().contains(failureCauseString));
+        assertEquals("AuthenticationResult has the wrong Principal",
+                     null, authenticationResult.getMainPrincipal());
+    }
+
+    private OAuth2MockEndpoint createMockTokenEndpoint()
+    {
+        OAuth2MockEndpoint tokenEndpoint = new OAuth2MockEndpoint();
+        tokenEndpoint.putExpectedParameter("grant_type", "authorization_code");
+        tokenEndpoint.putExpectedParameter("response_type", "token");
+        tokenEndpoint.putExpectedParameter("code", TEST_VALID_AUTHORIZATION_CODE);
+        tokenEndpoint.putExpectedParameter("redirect_uri", TEST_REDIRECT_URI);
+        tokenEndpoint.putExpectedParameter("client_id", TEST_CLIENT_ID);
+        tokenEndpoint.putExpectedParameter("client_secret", TEST_CLIENT_SECRET);
+        tokenEndpoint.setExpectedMethod("POST");
+        tokenEndpoint.setNeedsAuth(true);
+        tokenEndpoint.setResponse(200, String.format("{\"access_token\":\"%s\","
+                                                     + "\"token_type\":\"bearer\","
+                                                     + "\"expires_in\":3600}",
+                                                     TEST_VALID_ACCESS_TOKEN));
+        return tokenEndpoint;
+    }
+
+    private OAuth2MockEndpoint createMockIdentityResolverEndpoint()
+    {
+        OAuth2MockEndpoint identityResolverEndpoint = new OAuth2MockEndpoint();
+        identityResolverEndpoint.putExpectedParameter("token", TEST_VALID_ACCESS_TOKEN);
+        identityResolverEndpoint.setExpectedMethod("POST");
+        identityResolverEndpoint.setNeedsAuth(true);
+        identityResolverEndpoint.setResponse(200, String.format("{\"user_name\":\"%s\"}", TEST_USER_NAME));
+        return identityResolverEndpoint;
+    }
+
+
+    private static final class TrustingTrustManager implements X509TrustManager
+    {
+        @Override
+        public void checkClientTrusted(
+                java.security.cert.X509Certificate[] certs, String authType)
+        {
+        }
+
+        @Override
+        public void checkServerTrusted(
+                java.security.cert.X509Certificate[] certs, String authType)
+        {
+        }
+
+        @Override
+        public java.security.cert.X509Certificate[] getAcceptedIssuers()
+        {
+            return null;
+        }
+    }
+
+    private static final class BlindHostnameVerifier implements HostnameVerifier
+    {
+        @Override
+        public boolean verify(String arg0, SSLSession arg1)
+        {
+            return true;
+        }
+    }
+}

Added: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpoint.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpoint.java?rev=1732094&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpoint.java (added)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpoint.java Wed Feb 24 12:00:42 2016
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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.qpid.server.security.auth.manager.oauth2;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.bind.DatatypeConverter;
+
+class OAuth2MockEndpoint
+{
+    private HttpServletResponse _servletResponse;
+    private Map<String, String> _expectedParameters = new HashMap<>();
+    private String _expectedMethod;
+    private String _responseString;
+    private int _responseCode = 200;
+    private String _redirectUrlString;
+    private boolean _needsAuth;
+
+    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException
+    {
+        _servletResponse = response;
+        response.setContentType("application/json");
+        if (_needsAuth)
+        {
+            String expected = "Basic " + DatatypeConverter.printBase64Binary((OAuth2AuthenticationProviderImplTest.TEST_CLIENT_ID + ":" + OAuth2AuthenticationProviderImplTest.TEST_CLIENT_SECRET).getBytes(
+                    OAuth2AuthenticationProviderImplTest.UTF8));
+            doAssertEquals("Authorization required",
+                           expected,
+                           request.getHeader("Authorization"));
+        }
+        if (_expectedMethod != null)
+        {
+            doAssertEquals("Request uses unexpected HTTP method", _expectedMethod, request.getMethod());
+        }
+        if (_expectedParameters != null)
+        {
+            Map<String, String[]> parameters = request.getParameterMap();
+            for (String expectedParameter : _expectedParameters.keySet())
+            {
+                doAssertTrue                                          (String.format("Request is missing parameter '%s'", expectedParameter),
+                             parameters.containsKey(expectedParameter));
+                String[] parameterValues = parameters.get(expectedParameter);
+                doAssertEquals                          (String.format                  ("Request has parameter '%s' specified more than once",
+                                                                       expectedParameter),
+                               1, parameterValues.length);
+                doAssertEquals                                                               (String.format("Request parameter '%s' has unexpected value", expectedParameter),
+                               _expectedParameters.get(expectedParameter), parameterValues[0]);
+            }
+        }
+        if (_redirectUrlString != null)
+        {
+            response.sendRedirect(_redirectUrlString);
+        }
+        else
+        {
+            if (_responseCode != 0)
+            {
+                response.setStatus(_responseCode);
+            }
+            response.getOutputStream().write(_responseString.getBytes(OAuth2AuthenticationProviderImplTest.UTF8));
+        }
+    }
+
+    public void putExpectedParameter(String key, String value)
+    {
+        _expectedParameters.put(key, value);
+    }
+
+    public void setExpectedMethod(final String expectedMethod)
+    {
+        _expectedMethod = expectedMethod;
+    }
+
+    public void setResponseString(final String responseString)
+    {
+        _responseString = responseString;
+    }
+
+    public void setResponseCode(final int responseCode)
+    {
+        _responseCode = responseCode;
+    }
+
+    public void setResponse(int code, String message)
+    {
+        setResponseCode(code);
+        setResponseString(message);
+    }
+
+    public void setRedirectUrlString(final String redirectUrlString)
+    {
+        _redirectUrlString = redirectUrlString;
+    }
+
+    public void setNeedsAuth(final boolean needsAuth)
+    {
+        this._needsAuth = needsAuth;
+    }
+
+    private void doAssertEquals(String msg, Object expected, Object actual) throws IOException
+    {
+        if ((expected == null && actual != null) || (expected != null && !expected.equals(actual)))
+        {
+            sendError(String.format("%s; Expected: '%s'; Actual: '%s'", msg, expected, actual));
+        }
+    }
+
+    private void doAssertTrue(String msg, boolean condition) throws IOException
+    {
+        if (!condition)
+        {
+            sendError(msg);
+        }
+    }
+
+    private void sendError(String errorDescription) throws IOException
+    {
+        _servletResponse.setStatus(500);
+        String responseString = String.format("{\"error\":\"test_failure\","
+                                              + "\"error_description\":\"%s\"}", errorDescription);
+        _servletResponse.getOutputStream().write(responseString.getBytes());
+        throw new AssertionError(responseString);
+    }
+}

Added: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpointHolder.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpointHolder.java?rev=1732094&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpointHolder.java (added)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2MockEndpointHolder.java Wed Feb 24 12:00:42 2016
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.qpid.server.security.auth.manager.oauth2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.server.ssl.SslSocketConnector;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+class OAuth2MockEndpointHolder
+{
+    private static final String KEYSTORE_PASSWORD = "password";
+    private static final String KEYSTORE_RESOURCE = "ssl/test_keystore.jks";
+    private final Server _server;
+    private final SslSocketConnector _connector;
+
+    OAuth2MockEndpointHolder(final Map<String, OAuth2MockEndpoint> endpoints)
+    {
+        _server = new Server();
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePassword(KEYSTORE_PASSWORD);
+        InputStream keyStoreInputStream = getClass().getClassLoader().getResourceAsStream(KEYSTORE_RESOURCE);
+        sslContextFactory.setKeyStoreInputStream(keyStoreInputStream);
+        _connector = new SslSocketConnector(sslContextFactory);
+        _connector.setPort(OAuth2AuthenticationProviderImplTest.TEST_ENDPOINT_PORT);
+        _server.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request,
+                               HttpServletResponse response) throws IOException,
+                                                                    ServletException
+            {
+                baseRequest.setHandled(true);
+
+                try
+                {
+                    final OAuth2MockEndpoint
+                            mockEndpoint = endpoints.get(request.getPathInfo());
+                    TestCase.assertNotNull(String.format("Could not find mock endpoint for request path '%s'",
+                                                         request.getPathInfo()), mockEndpoint);
+                    if (mockEndpoint != null)
+                    {
+                        mockEndpoint.handleRequest(request, response);
+                    }
+                }
+                catch (Throwable t)
+                {
+                    response.setStatus(500);
+                    response.getOutputStream().write(String.format("{\"error\":\"test failure\",\"error_description\":\"%s\"}", t)
+                                                           .getBytes(OAuth2AuthenticationProviderImplTest.UTF8));
+                }
+            }
+        });
+        _server.addConnector(_connector);
+    }
+
+    public void start() throws Exception
+    {
+        _server.start();
+    }
+
+    public void stop() throws Exception
+    {
+        _server.stop();
+    }
+
+    public int getPort()
+    {
+        return _connector.getLocalPort();
+    }
+}

Added: qpid/java/trunk/broker-core/src/test/resources/ssl/test_keystore.jks
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/resources/ssl/test_keystore.jks?rev=1732094&view=auto
==============================================================================
Binary files qpid/java/trunk/broker-core/src/test/resources/ssl/test_keystore.jks (added) and qpid/java/trunk/broker-core/src/test/resources/ssl/test_keystore.jks Wed Feb 24 12:00:42 2016 differ

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticator.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticator.java?rev=1732094&r1=1732093&r2=1732094&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticator.java (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticator.java Wed Feb 24 12:00:42 2016
@@ -54,11 +54,11 @@ import org.apache.qpid.server.security.a
 public class OAuth2InteractiveAuthenticator implements HttpRequestInteractiveAuthenticator
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2InteractiveAuthenticator.class);
-    private static final int STATE_NONCE_BIT_SIZE = 256;
-    private static final String STATE_NAME = "stateNonce";
     private static final String TYPE = "OAuth2";
-    private static final String ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE = "originalRequestURI";
-    private static final String REDIRECT_URI_SESSION_ATTRIBUTE = "redirectURI";
+    private static final int STATE_NONCE_BIT_SIZE = 256;
+    static final String STATE_NAME = "stateNonce";
+    static final String REDIRECT_URI_SESSION_ATTRIBUTE = "redirectURI";
+    static final String ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE = "originalRequestURI";
 
     /** Authentication Endpoint error responses https://tools.ietf.org/html/rfc6749#section-4.2.2.1 */
     private static final Map<String, Integer> ERROR_RESPONSES;

Added: qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticatorTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticatorTest.java?rev=1732094&view=auto
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticatorTest.java (added)
+++ qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2InteractiveAuthenticatorTest.java Wed Feb 24 12:00:42 2016
@@ -0,0 +1,389 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.auth;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.server.AbstractHttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpRequestInteractiveAuthenticator;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2AuthenticationProvider;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class OAuth2InteractiveAuthenticatorTest extends QpidTestCase
+{
+    private static final String TEST_AUTHORIZATION_ENDPOINT = "testAuthEndpoint";
+    private static final int TEST_PORT = 64756;
+    private static final int TEST_REMOTE_PORT = 0;
+    private static final String TEST_OAUTH2_SCOPE = "testScope";
+    private static final String TEST_REQUEST_HOST = "http://localhost";
+    private static final String TEST_REQUEST_PATH = "/foo/bar";
+    private static final String TEST_REQUEST_QUERY = "?baz=fnord";
+    private static final String TEST_REQUEST = TEST_REQUEST_HOST + ":" + TEST_PORT + TEST_REQUEST_PATH + TEST_REQUEST_QUERY;
+    private static final String TEST_CLIENT_ID = "testClientId";
+    private static final String TEST_STATE = "testState";
+    private static final String TEST_VALID_AUTHORIZATION_CODE = "testValidAuthorizationCode";
+    private static final String TEST_INVALID_AUTHORIZATION_CODE = "testInvalidAuthorizationCode";
+    private static final String TEST_UNAUTHORIZED_AUTHORIZATION_CODE = "testUnauthorizedAuthorizationCode";
+    private static final String TEST_AUTHORIZED_USER = "testAuthorizedUser";
+    private static final String TEST_UNAUTHORIZED_USER = "testUnauthorizedUser";
+    private static final String ATTR_SUBJECT = "Qpid.subject"; // this is private in HttpManagementUtil
+    public static final String TEST_REMOTE_HOST = "testRemoteHost";
+
+    private OAuth2InteractiveAuthenticator _authenticator;
+    private HttpManagementConfiguration _mockConfiguration;
+    private OAuth2AuthenticationProvider<?> _mockAuthProvider;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        _mockAuthProvider = createMockOAuth2AuthenticationProvider();
+        _mockConfiguration = mock(HttpManagementConfiguration.class);
+        when(_mockConfiguration.getAuthenticationProvider(any(HttpServletRequest.class))).thenReturn(_mockAuthProvider);
+
+        _authenticator = new OAuth2InteractiveAuthenticator();
+    }
+
+    public void testInitialRedirect() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH,
+                                                           Collections.singletonMap("baz", "fnord"), sessionAttributes);
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator has failed unexpectedly", !(authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler));
+
+        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+        authenticationHandler.handleAuthentication(mockResponse);
+
+        ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
+        verify(mockResponse).sendRedirect(argument.capture());
+        Map<String, String> params = getRedirectParameters(argument.getValue());
+
+        assertTrue("Wrong redirect host", argument.getValue().startsWith(TEST_AUTHORIZATION_ENDPOINT));
+        assertEquals("Wrong response_type", "code", params.get("response_type"));
+        assertEquals("Wrong client_id", TEST_CLIENT_ID, params.get("client_id"));
+        assertEquals("Wrong redirect_uri", TEST_REQUEST_HOST, params.get("redirect_uri"));
+        assertEquals("Wrong scope", TEST_OAUTH2_SCOPE, params.get("scope"));
+        assertNotNull("State was not set on the session",
+                      sessionAttributes.get(OAuth2InteractiveAuthenticator.STATE_NAME));
+        assertEquals("Wrong state",
+                     (String) sessionAttributes.get(OAuth2InteractiveAuthenticator.STATE_NAME),
+                     params.get("state"));
+    }
+
+    public void testValidLogin() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        requestParameters.put("state", TEST_STATE);
+        requestParameters.put("code", TEST_VALID_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator has failed unexpectedly", !(authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler));
+
+        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+        authenticationHandler.handleAuthentication(mockResponse);
+
+        ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
+        verify(mockResponse).sendRedirect(argument.capture());
+
+        assertEquals("Wrong redirect", TEST_REQUEST, argument.getValue());
+        assertNotNull("No subject on session", sessionAttributes.get(ATTR_SUBJECT));
+        assertTrue("Subject on session is no a Subject", sessionAttributes.get(ATTR_SUBJECT) instanceof Subject);
+        final Set<Principal> principals = ((Subject) sessionAttributes.get(ATTR_SUBJECT)).getPrincipals();
+        assertEquals("Subject created with unexpected principal", TEST_AUTHORIZED_USER, principals.iterator().next().getName());
+    }
+
+    public void testNoStateOnSession() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        //sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        requestParameters.put("state", TEST_STATE);
+        requestParameters.put("code", TEST_VALID_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator did not fail with no state on session", authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler);
+    }
+
+    public void testNoStateOnRequest() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        //requestParameters.put("state", TEST_STATE);
+        requestParameters.put("code", TEST_VALID_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator did not fail with no state on request", authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler);
+    }
+
+    public void testWrongStateOnRequest() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        requestParameters.put("state", "WRONG" + TEST_STATE);
+        requestParameters.put("code", TEST_VALID_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator did not fail with wrong state on request", authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler);
+    }
+
+    public void testInvalidAuthorizationCode() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        requestParameters.put("state", TEST_STATE);
+        requestParameters.put("code", TEST_INVALID_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator has failed unexpectedly", !(authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler));
+
+        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+        try
+        {
+            authenticationHandler.handleAuthentication(mockResponse);
+            fail("Authentication with invalid authorization code should not succeed");
+        }
+        catch (SecurityException e)
+        {
+            // pass
+        }
+    }
+
+    public void testUnauthorizedAuthorizationCode() throws Exception
+    {
+        Map<String, Object> sessionAttributes = new HashMap<>();
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.STATE_NAME, TEST_STATE);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.ORIGINAL_REQUEST_URI_SESSION_ATTRIBUTE, TEST_REQUEST);
+        sessionAttributes.put(OAuth2InteractiveAuthenticator.REDIRECT_URI_SESSION_ATTRIBUTE, TEST_REQUEST_HOST);
+        Map<String, String> requestParameters = new HashMap<>();
+        requestParameters.put("state", TEST_STATE);
+        requestParameters.put("code", TEST_UNAUTHORIZED_AUTHORIZATION_CODE);
+        HttpServletRequest mockRequest = createMockRequest(TEST_REQUEST_HOST, TEST_REQUEST_PATH, requestParameters, sessionAttributes);
+
+        HttpRequestInteractiveAuthenticator.AuthenticationHandler authenticationHandler = _authenticator.getAuthenticationHandler(mockRequest,
+                                                                                                                                  _mockConfiguration);
+        assertNotNull("Authenticator does not feel responsible", authenticationHandler);
+        assertTrue("Authenticator has failed unexpectedly", !(authenticationHandler instanceof OAuth2InteractiveAuthenticator.FailedAuthenticationHandler));
+
+        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+        authenticationHandler.handleAuthentication(mockResponse);
+        verify(mockResponse).sendError(eq(403), any(String.class));
+    }
+
+    private Map<String, String> getRedirectParameters(final String redirectLocation)
+    {
+        AbstractHttpConnection mockConnection = mock(AbstractHttpConnection.class);
+        HttpFields requestFields = new HttpFields();
+        when(mockConnection.getRequestFields()).thenReturn(requestFields);
+        Request request = new Request(mockConnection);
+        request.setUri(new HttpURI(redirectLocation));
+        request.setRequestURI(redirectLocation);
+        request.setContentType("text/html");
+        final Map<String,String[]> parameterMap = request.getParameterMap();
+        Map<String,String> parameters = new HashMap<>();
+        for (Map.Entry<String, String[]> paramEntry : parameterMap.entrySet())
+        {
+            assertEquals(String.format("param '%s' specified more than once", paramEntry.getKey()), 1, paramEntry.getValue().length);
+            parameters.put(paramEntry.getKey(), paramEntry.getValue()[0]);
+        }
+        return parameters;
+    }
+
+    private OAuth2AuthenticationProvider<?> createMockOAuth2AuthenticationProvider() throws URISyntaxException
+    {
+        OAuth2AuthenticationProvider authenticationProvider = mock(OAuth2AuthenticationProvider.class);
+        Broker mockBroker = mock(Broker.class);
+        SecurityManager mockSecurityManager = mock(SecurityManager.class);
+        SubjectCreator mockSubjectCreator = mock(SubjectCreator.class);
+        SubjectAuthenticationResult mockSuccessfulSubjectAuthenticationResult = mock(SubjectAuthenticationResult.class);
+        SubjectAuthenticationResult mockUnauthorizedSubjectAuthenticationResult = mock(SubjectAuthenticationResult.class);
+        final Subject successfulSubject = new Subject(true, Collections.singleton(new AuthenticatedPrincipal(
+                TEST_AUTHORIZED_USER)), Collections.emptySet(), Collections.emptySet());
+        final Subject unauthorizedSubject = new Subject(true, Collections.singleton(new AuthenticatedPrincipal(
+                TEST_UNAUTHORIZED_USER)), Collections.emptySet(), Collections.emptySet());
+        AuthenticationResult mockSuccessfulAuthenticationResult = mock(AuthenticationResult.class);
+        AuthenticationResult mockUnauthorizedAuthenticationResult = mock(AuthenticationResult.class);
+        AuthenticationResult failedAuthenticationResult = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,
+                                                                                   new Exception("authentication failed"));
+        SubjectAuthenticationResult failedSubjectAuthenticationResult = new SubjectAuthenticationResult(failedAuthenticationResult);
+
+        doAnswer(new Answer()
+        {
+            @Override
+            public Object answer(final InvocationOnMock invocationOnMock) throws Throwable
+            {
+                final Subject subject = Subject.getSubject(AccessController.getContext());
+                if (!subject.getPrincipals().iterator().next().getName().equals(TEST_AUTHORIZED_USER))
+                {
+                    throw new AccessControlException("access denied");
+                }
+                return null;
+            }
+        }).when(mockSecurityManager).accessManagement();
+        when(mockBroker.getSecurityManager()).thenReturn(mockSecurityManager);
+
+        when(authenticationProvider.getAuthorizationEndpointURI()).thenReturn(new URI(TEST_AUTHORIZATION_ENDPOINT));
+        when(authenticationProvider.getClientId()).thenReturn(TEST_CLIENT_ID);
+        when(authenticationProvider.getScope()).thenReturn(TEST_OAUTH2_SCOPE);
+        when(authenticationProvider.getParent(Broker.class)).thenReturn(mockBroker);
+        when(authenticationProvider.getSubjectCreator(any(Boolean.class))).thenReturn(mockSubjectCreator);
+        when(authenticationProvider.authenticateViaAuthorizationCode(TEST_VALID_AUTHORIZATION_CODE, TEST_REQUEST_HOST)).thenReturn(mockSuccessfulAuthenticationResult);
+        when(authenticationProvider.authenticateViaAuthorizationCode(TEST_INVALID_AUTHORIZATION_CODE, TEST_REQUEST_HOST)).thenReturn(failedAuthenticationResult);
+        when(authenticationProvider.authenticateViaAuthorizationCode(TEST_UNAUTHORIZED_AUTHORIZATION_CODE, TEST_REQUEST_HOST)).thenReturn(mockUnauthorizedAuthenticationResult);
+
+        when(mockSuccessfulSubjectAuthenticationResult.getSubject()).thenReturn(successfulSubject);
+        when(mockUnauthorizedSubjectAuthenticationResult.getSubject()).thenReturn(unauthorizedSubject);
+
+        when(mockSubjectCreator.createResultWithGroups(mockSuccessfulAuthenticationResult)).thenReturn(mockSuccessfulSubjectAuthenticationResult);
+        when(mockSubjectCreator.createResultWithGroups(mockUnauthorizedAuthenticationResult)).thenReturn(mockUnauthorizedSubjectAuthenticationResult);
+        when(mockSubjectCreator.createResultWithGroups(failedAuthenticationResult)).thenReturn(failedSubjectAuthenticationResult);
+
+        return authenticationProvider;
+    }
+
+    private HttpServletRequest createMockRequest(String host, String path,
+                                                 final Map<String, String> query,
+                                                 Map<String, Object> sessionAttributes) throws IOException
+    {
+        final HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        when(mockRequest.getParameterNames()).thenReturn(Collections.enumeration(query.keySet()));
+        doAnswer(new Answer()
+        {
+            @Override
+            public Object answer(final InvocationOnMock invocationOnMock) throws Throwable
+            {
+                final Object[] arguments = invocationOnMock.getArguments();
+                assertEquals("Unexpected number of arguments", 1, arguments.length);
+                final String paramName = (String) arguments[0];
+                return new String[]{query.get(paramName)};
+            }
+        }).when(mockRequest).getParameterValues(any(String.class));
+        when(mockRequest.isSecure()).thenReturn(false);
+        final HttpSession mockHttpSession = createMockHttpSession(sessionAttributes);
+        when(mockRequest.getSession()).thenReturn(mockHttpSession);
+        when(mockRequest.getServletPath()).thenReturn("");
+        when(mockRequest.getPathInfo()).thenReturn(path);
+        final StringBuffer url = new StringBuffer(host + path);
+        when(mockRequest.getRequestURL()).thenReturn(url);
+        when(mockRequest.getRemoteHost()).thenReturn(TEST_REMOTE_HOST);
+        when(mockRequest.getRemotePort()).thenReturn(TEST_REMOTE_PORT);
+        return mockRequest;
+    }
+
+    private HttpSession createMockHttpSession(final Map<String, Object> sessionAttributes)
+    {
+        final HttpSession httpSession = mock(HttpSession.class);
+        doAnswer(new Answer()
+        {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable
+            {
+                final Object[] arguments = invocation.getArguments();
+                assertEquals(2, arguments.length);
+                sessionAttributes.put((String) arguments[0], arguments[1]);
+                return null;
+            }
+        }).when(httpSession).setAttribute(any(String.class), any(Object.class));
+        doAnswer(new Answer()
+        {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable
+            {
+                final Object[] arguments = invocation.getArguments();
+                assertEquals(1, arguments.length);
+                return sessionAttributes.get((String) arguments[0]);
+            }
+        }).when(httpSession).getAttribute(any(String.class));
+        ServletContext mockServletContext = mock(ServletContext.class);
+        when(httpSession.getServletContext()).thenReturn(mockServletContext);
+        return httpSession;
+    }
+}

Added: qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2PreemptiveAuthenticatorTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2PreemptiveAuthenticatorTest.java?rev=1732094&view=auto
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2PreemptiveAuthenticatorTest.java (added)
+++ qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/auth/OAuth2PreemptiveAuthenticatorTest.java Wed Feb 24 12:00:42 2016
@@ -0,0 +1,136 @@
+/*
+ * 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.qpid.server.management.plugin.auth;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2AuthenticationProvider;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class OAuth2PreemptiveAuthenticatorTest extends QpidTestCase
+{
+    private static final String TEST_AUTHORIZED_USER = "testAuthorizedUser";
+    private static final String TEST_UNAUTHORIZED_USER = "testUnauthorizedUser";
+    private static final String TEST_VALID_ACCESS_TOKEN = "testValidAccessToken";
+    private static final String TEST_INVALID_ACCESS_TOKEN = "testInvalidAccessToken";
+    private static final String TEST_UNAUTHORIZED_ACCESS_TOKEN = "testUnauthorizedAccessToken";
+
+    private OAuth2PreemptiveAuthenticator _authenticator;
+    private HttpManagementConfiguration _mockConfiguration;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        OAuth2AuthenticationProvider<?> mockAuthProvider = createMockOAuth2AuthenticationProvider();
+        _mockConfiguration = mock(HttpManagementConfiguration.class);
+        when(_mockConfiguration.getAuthenticationProvider(any(HttpServletRequest.class))).thenReturn(mockAuthProvider);
+
+        _authenticator = new OAuth2PreemptiveAuthenticator();
+    }
+
+    public void testAttemptAuthenticationSuccessful() throws Exception
+    {
+        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + TEST_VALID_ACCESS_TOKEN);
+        Subject subject = _authenticator.attemptAuthentication(mockRequest, _mockConfiguration);
+        assertNotNull("Authenticator failed unexpectedly", subject);
+        final Set<Principal> principals = subject.getPrincipals();
+        assertEquals("Subject created with unexpected principal", TEST_AUTHORIZED_USER, principals.iterator().next().getName());
+    }
+
+    public void testAttemptAuthenticationUnauthorizedUser() throws Exception
+    {
+        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + TEST_UNAUTHORIZED_ACCESS_TOKEN);
+        Subject subject = _authenticator.attemptAuthentication(mockRequest, _mockConfiguration);
+        assertNotNull("Authenticator failed unexpectedly", subject);
+        final Set<Principal> principals = subject.getPrincipals();
+        assertEquals("Subject created with unexpected principal", TEST_UNAUTHORIZED_USER, principals.iterator().next().getName());
+    }
+
+    public void testAttemptAuthenticationInvalidToken() throws Exception
+    {
+        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + TEST_INVALID_ACCESS_TOKEN);
+        Subject subject = _authenticator.attemptAuthentication(mockRequest, _mockConfiguration);
+        assertNull("Authenticator did not fail with invalid access token", subject);
+    }
+
+    public void testAttemptAuthenticationMissingHeader() throws Exception
+    {
+        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        Subject subject = _authenticator.attemptAuthentication(mockRequest, _mockConfiguration);
+        assertNull("Authenticator did not failed without authentication header", subject);
+    }
+
+    public void testAttemptAuthenticationMalformedHeader() throws Exception
+    {
+        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+        when(mockRequest.getHeader("Authorization")).thenReturn("malformed Bearer " + TEST_UNAUTHORIZED_ACCESS_TOKEN);
+        Subject subject = _authenticator.attemptAuthentication(mockRequest, _mockConfiguration);
+        assertNull("Authenticator did not failed with malformed authentication header", subject);
+    }
+
+    private OAuth2AuthenticationProvider<?> createMockOAuth2AuthenticationProvider() throws URISyntaxException
+    {
+        OAuth2AuthenticationProvider authenticationProvider = mock(OAuth2AuthenticationProvider.class);
+        SubjectCreator mockSubjectCreator = mock(SubjectCreator.class);
+        SubjectAuthenticationResult mockSuccessfulSubjectAuthenticationResult = mock(SubjectAuthenticationResult.class);
+        SubjectAuthenticationResult mockUnauthorizedSubjectAuthenticationResult = mock(SubjectAuthenticationResult.class);
+        final Subject successfulSubject = new Subject(true, Collections.singleton(new AuthenticatedPrincipal(
+                TEST_AUTHORIZED_USER)), Collections.emptySet(), Collections.emptySet());
+        final Subject unauthorizedSubject = new Subject(true, Collections.singleton(new AuthenticatedPrincipal(
+                TEST_UNAUTHORIZED_USER)), Collections.emptySet(), Collections.emptySet());
+        AuthenticationResult mockSuccessfulAuthenticationResult = mock(AuthenticationResult.class);
+        AuthenticationResult mockUnauthorizedAuthenticationResult = mock(AuthenticationResult.class);
+        AuthenticationResult failedAuthenticationResult = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,
+                                                                                   new Exception("authentication failed"));
+        SubjectAuthenticationResult failedSubjectAuthenticationResult = new SubjectAuthenticationResult(failedAuthenticationResult);
+
+        when(authenticationProvider.getSubjectCreator(any(Boolean.class))).thenReturn(mockSubjectCreator);
+        when(authenticationProvider.authenticateViaAccessToken(TEST_VALID_ACCESS_TOKEN)).thenReturn(mockSuccessfulAuthenticationResult);
+        when(authenticationProvider.authenticateViaAccessToken(TEST_INVALID_ACCESS_TOKEN)).thenReturn(failedAuthenticationResult);
+        when(authenticationProvider.authenticateViaAccessToken(TEST_UNAUTHORIZED_ACCESS_TOKEN)).thenReturn(mockUnauthorizedAuthenticationResult);
+
+        when(mockSuccessfulSubjectAuthenticationResult.getSubject()).thenReturn(successfulSubject);
+        when(mockUnauthorizedSubjectAuthenticationResult.getSubject()).thenReturn(unauthorizedSubject);
+
+        when(mockSubjectCreator.createResultWithGroups(mockSuccessfulAuthenticationResult)).thenReturn(mockSuccessfulSubjectAuthenticationResult);
+        when(mockSubjectCreator.createResultWithGroups(mockUnauthorizedAuthenticationResult)).thenReturn(mockUnauthorizedSubjectAuthenticationResult);
+        when(mockSubjectCreator.createResultWithGroups(failedAuthenticationResult)).thenReturn(failedSubjectAuthenticationResult);
+
+        return authenticationProvider;
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org