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: [email protected]
For additional commands, e-mail: [email protected]