From 1c6f082b07382d0f2562364e460ff2c3f8ec19a9 Mon Sep 17 00:00:00 2001 From: Ray Lee Date: Sat, 23 Dec 2017 16:00:59 -0800 Subject: [PATCH] DRYD-203: Expect passwords to be base64-encoded on oauth2 password grant requests. --- .../test/JsonIntegrationTest.java | 7 +- .../security-oauth/password-grant-admin.txt | 2 +- .../password-grant-bad-password.txt | 2 +- .../security-oauth/password-grant-reader.txt | 2 +- .../src/main/webapp/WEB-INF/oauth-servlet.xml | 12 ++- services/authorization/service/pom.xml | 6 ++ .../spring/CSpaceOAuth2RequestFactory.java | 100 ++++++++++++++++++ 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 services/authorization/service/src/main/java/org/collectionspace/services/authorization/spring/CSpaceOAuth2RequestFactory.java diff --git a/services/IntegrationTests/src/test/java/org/collectionspace/services/IntegrationTests/test/JsonIntegrationTest.java b/services/IntegrationTests/src/test/java/org/collectionspace/services/IntegrationTests/test/JsonIntegrationTest.java index 94a510289..fb14d6308 100644 --- a/services/IntegrationTests/src/test/java/org/collectionspace/services/IntegrationTests/test/JsonIntegrationTest.java +++ b/services/IntegrationTests/src/test/java/org/collectionspace/services/IntegrationTests/test/JsonIntegrationTest.java @@ -2,6 +2,9 @@ package org.collectionspace.services.IntegrationTests.test; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.xml.bind.DatatypeConverter; import static org.testng.Assert.*; @@ -77,9 +80,11 @@ public class JsonIntegrationTest { @Test public void testAuth() throws ClientProtocolException, IOException { + String base64EncodedPassword = DatatypeConverter.printBase64Binary(PASSWORD.getBytes(StandardCharsets.UTF_8)); + JsonNode jsonNode; - jsonNode = postAuthForm("oauth/token", "grant_type=password&username=" + USERNAME + "&password=" + PASSWORD); + jsonNode = postAuthForm("oauth/token", "grant_type=password&username=" + USERNAME + "&password=" + base64EncodedPassword); assertEquals(jsonNode.at("/token_type").asText(), "bearer"); assertTrue(StringUtils.isNotEmpty(jsonNode.at("/access_token").asText())); diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-admin.txt b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-admin.txt index 0bf30694e..6c1f1ec06 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-admin.txt +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-admin.txt @@ -1 +1 @@ -grant_type=password&username=admin@core.collectionspace.org&password=Administrator \ No newline at end of file +grant_type=password&username=admin@core.collectionspace.org&password=QWRtaW5pc3RyYXRvcg%3D%3D \ No newline at end of file diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-bad-password.txt b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-bad-password.txt index 1a5022c1a..40b4a0540 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-bad-password.txt +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-bad-password.txt @@ -1 +1 @@ -grant_type=password&username=admin@core.collectionspace.org&password=NotThePassword \ No newline at end of file +grant_type=password&username=admin@core.collectionspace.org&password=NotTheBase64EncodedPassword \ No newline at end of file diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-reader.txt b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-reader.txt index b74be9dc5..d0ed77a65 100644 --- a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-reader.txt +++ b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/security-oauth/password-grant-reader.txt @@ -1 +1 @@ -grant_type=password&username=reader@core.collectionspace.org&password=reader \ No newline at end of file +grant_type=password&username=reader@core.collectionspace.org&password=cmVhZGVy \ No newline at end of file diff --git a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/oauth-servlet.xml b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/oauth-servlet.xml index bc408d066..2f3796353 100644 --- a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/oauth-servlet.xml +++ b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/oauth-servlet.xml @@ -7,7 +7,11 @@ http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd"> - + @@ -15,7 +19,11 @@ - + + + + + diff --git a/services/authorization/service/pom.xml b/services/authorization/service/pom.xml index 0cb33a980..2f13b965e 100644 --- a/services/authorization/service/pom.xml +++ b/services/authorization/service/pom.xml @@ -101,6 +101,12 @@ ${spring.security.version} provided + + org.springframework.security.oauth + spring-security-oauth2 + ${spring.security.oauth2.version} + provided + org.springframework spring-context diff --git a/services/authorization/service/src/main/java/org/collectionspace/services/authorization/spring/CSpaceOAuth2RequestFactory.java b/services/authorization/service/src/main/java/org/collectionspace/services/authorization/spring/CSpaceOAuth2RequestFactory.java new file mode 100644 index 000000000..7cd8075ca --- /dev/null +++ b/services/authorization/service/src/main/java/org/collectionspace/services/authorization/spring/CSpaceOAuth2RequestFactory.java @@ -0,0 +1,100 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + *//** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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.collectionspace.services.authorization.spring; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.DatatypeConverter; + +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.TokenRequest; +import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory; + +/** + * An OAuth2RequestFactory that expects the password to be base64 encoded. This implementation + * copies the parameters, decodes the password if present, and passes the result to + * DefaultOAuth2RequestFactory. + */ +public class CSpaceOAuth2RequestFactory extends DefaultOAuth2RequestFactory { + private final String PASSWORD_PARAMETER = "password"; + + public CSpaceOAuth2RequestFactory(ClientDetailsService clientDetailsService) { + super(clientDetailsService); + } + + @Override + public AuthorizationRequest createAuthorizationRequest( + Map authorizationParameters) { + return super.createAuthorizationRequest(decodePassword(authorizationParameters)); + } + + @Override + public TokenRequest createTokenRequest( + Map requestParameters, + ClientDetails authenticatedClient) { + return super.createTokenRequest(decodePassword(requestParameters), authenticatedClient); + } + + private Map decodePassword(Map parameters) { + if (parameters.containsKey(PASSWORD_PARAMETER)) { + String base64EncodedPassword = parameters.get(PASSWORD_PARAMETER); + String password = new String(DatatypeConverter.parseBase64Binary(base64EncodedPassword), StandardCharsets.UTF_8); + + Map parametersCopy = new HashMap(parameters); + + parametersCopy.put(PASSWORD_PARAMETER, password); + + return parametersCopy; + } + + return parameters; + } +} -- 2.47.3