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