From e0d42d7c929681b58c196435f869d96da1bb56be Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 9 Feb 2017 20:52:53 +0100 Subject: [PATCH] change authentication parameters to match oauth spec --- .../scm/client/JerseyClientProvider.java | 1 + .../java/sonia/scm/url/RestUrlProvider.java | 4 +-- .../scm/url/RestUrlProviderTestBase.java | 4 +-- .../resources/AuthenticationResource.java | 28 +++++++++---------- .../java/sonia/scm/filter/SecurityFilter.java | 2 +- .../resources/js/login/sonia.login.form.js | 11 +++++++- .../src/main/webapp/resources/js/sonia.scm.js | 4 +-- .../scm/it/AuthorizationScopeITCase.java | 10 ++++--- .../sonia/scm/it/IntegrationTestUtil.java | 13 ++++----- 9 files changed, 44 insertions(+), 33 deletions(-) diff --git a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyClientProvider.java b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyClientProvider.java index f02420f07a..eb9825d470 100644 --- a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyClientProvider.java +++ b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyClientProvider.java @@ -194,6 +194,7 @@ public class JerseyClientProvider implements ScmClientProvider formData.add("username", username); formData.add("password", password); + formData.add("grant_type", "password"); return resource.type("application/x-www-form-urlencoded").post( ClientResponse.class, formData); diff --git a/scm-core/src/main/java/sonia/scm/url/RestUrlProvider.java b/scm-core/src/main/java/sonia/scm/url/RestUrlProvider.java index 50f5912edb..4abba6db0b 100644 --- a/scm-core/src/main/java/sonia/scm/url/RestUrlProvider.java +++ b/scm-core/src/main/java/sonia/scm/url/RestUrlProvider.java @@ -48,7 +48,7 @@ public class RestUrlProvider implements UrlProvider public static final String PART_API = "api/rest/"; /** Field description */ - public static final String PART_AUTHENTICATION = "authentication/login"; + public static final String PART_AUTHENTICATION = "auth/access_token"; /** Field description */ public static final String PART_CONFIG = "config"; @@ -60,7 +60,7 @@ public class RestUrlProvider implements UrlProvider public static final String PART_REPOSITORIES = "repositories"; /** Field description */ - public static final String PART_STATE = "authentication"; + public static final String PART_STATE = "auth"; /** Field description */ public static final String PART_USER = "users"; diff --git a/scm-core/src/test/java/sonia/scm/url/RestUrlProviderTestBase.java b/scm-core/src/test/java/sonia/scm/url/RestUrlProviderTestBase.java index 3f995d57c3..3b39e22816 100644 --- a/scm-core/src/test/java/sonia/scm/url/RestUrlProviderTestBase.java +++ b/scm-core/src/test/java/sonia/scm/url/RestUrlProviderTestBase.java @@ -76,7 +76,7 @@ public abstract class RestUrlProviderTestBase extends UrlProviderTestBase @Override protected String getExpectedAuthenticationUrl(String baseUrl) { - return createRestUrl(baseUrl, "authentication/login"); + return createRestUrl(baseUrl, "auth/access_token"); } /** @@ -104,6 +104,6 @@ public abstract class RestUrlProviderTestBase extends UrlProviderTestBase @Override protected String getExpectedStateUrl(String baseUrl) { - return createRestUrl(baseUrl, "authentication"); + return createRestUrl(baseUrl, "auth"); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java index 68b58095c1..9a717deb20 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java @@ -67,7 +67,6 @@ import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -86,7 +85,7 @@ import sonia.scm.security.Scope; * @author Sebastian Sdorra */ @Singleton -@Path("authentication") +@Path("auth") @ExternallyManagedLifecycle @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public class AuthenticationResource @@ -140,6 +139,7 @@ public class AuthenticationResource * * @param request current http request * @param response current http response + * @param grantType grant type, currently only password is supported * @param username the username for the authentication * @param password the password for the authentication * @param cookie create authentication token @@ -148,19 +148,20 @@ public class AuthenticationResource * @return */ @POST - @Path("login") + @Path("access_token") @TypeHint(ScmState.class) - public Response authenticate(@Context HttpServletRequest request, + public Response authenticate( + @Context HttpServletRequest request, @Context HttpServletResponse response, + @FormParam("grant_type") String grantType, @FormParam("username") String username, @FormParam("password") String password, - @QueryParam("cookie") boolean cookie, - @QueryParam("scope") List scope) + @FormParam("cookie") boolean cookie, + @FormParam("scope") List scope) { - Preconditions.checkArgument(!Strings.isNullOrEmpty(username), - "username parameter is required"); - Preconditions.checkArgument(!Strings.isNullOrEmpty(password), - "password parameter is required"); + Preconditions.checkArgument(!Strings.isNullOrEmpty(grantType), "grant_type parameter is required"); + Preconditions.checkArgument(!Strings.isNullOrEmpty(username), "username parameter is required"); + Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "password parameter is required"); Response res; Subject subject = SecurityUtils.getSubject(); @@ -168,6 +169,7 @@ public class AuthenticationResource try { subject.login(Tokens.createAuthenticationToken(request, username, password)); + AccessTokenBuilder tokenBuilder = tokenBuilderFactory.create(); if ( scope != null ) { tokenBuilder.scope(Scope.valueOf(scope)); @@ -211,8 +213,7 @@ public class AuthenticationResource } else { - logger.warn("authentication failed, account {} is temporary locked", - username); + logger.warn("authentication failed, account {} is temporary locked", username); } res = handleFailedAuthentication(request, ex, Response.Status.FORBIDDEN, @@ -229,8 +230,7 @@ public class AuthenticationResource logger.warn("authentication failed for user {}", username); } - res = handleFailedAuthentication(request, ex, - Response.Status.UNAUTHORIZED, + res = handleFailedAuthentication(request, ex, Response.Status.UNAUTHORIZED, WUIAuthenticationFailure.WRONG_CREDENTIALS); } diff --git a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java index 7f5366ae1c..e94b6a3aee 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java @@ -70,7 +70,7 @@ public class SecurityFilter extends HttpFilter static final String ATTRIBUTE_REMOTE_USER = "principal"; /** Field description */ - public static final String URL_AUTHENTICATION = "/api/rest/authentication"; + public static final String URL_AUTHENTICATION = "/api/rest/auth"; //~--- constructors --------------------------------------------------------- diff --git a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js index 74336ace21..3b14ae2978 100644 --- a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js +++ b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js @@ -61,7 +61,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ var config = { labelWidth: 120, - url: restUrl + "authentication/login.json?cookie=true", + url: restUrl + "auth/access_token.json", frame: true, title: this.titleText, defaultType: 'textfield', @@ -93,6 +93,14 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ scope: this } } + }, { + name: 'grant_type', + value: 'password', + xtype: 'hidden' + }, { + name: 'cookie', + value: 'true', + xtype: 'hidden' }], buttons: buttons }; @@ -110,6 +118,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ authenticate: function(){ var form = this.getForm(); + form.submit({ scope: this, method: 'POST', diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js index 6d7e6a3257..0efa7b2585 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js @@ -339,7 +339,7 @@ Sonia.scm.Main = Ext.extend(Ext.util.Observable, { checkLogin: function(){ Ext.Ajax.request({ - url: restUrl + 'authentication/state.json', + url: restUrl + 'auth/state.json', method: 'GET', scope: this, success: function(response){ @@ -367,7 +367,7 @@ Sonia.scm.Main = Ext.extend(Ext.util.Observable, { logout: function(){ Ext.Ajax.request({ - url: restUrl + 'authentication/logout.json', + url: restUrl + 'auth/logout.json', method: 'GET', scope: this, success: function(response){ diff --git a/scm-webapp/src/test/java/sonia/scm/it/AuthorizationScopeITCase.java b/scm-webapp/src/test/java/sonia/scm/it/AuthorizationScopeITCase.java index f5a4afd7c2..d7b06d93b3 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/AuthorizationScopeITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/AuthorizationScopeITCase.java @@ -108,15 +108,17 @@ public class AuthorizationScopeITCase { private String createAuthenticationToken(String scope) { Client client = createClient(); - String url = createResourceUrl("authentication/login"); - if (!Strings.isNullOrEmpty(scope)) { - url = url.concat("?scope=").concat(scope); - } + String url = createResourceUrl("auth/access_token"); + WebResource wr = client.resource(url); MultivaluedMap formData = new MultivaluedMapImpl(); formData.add("username", ADMIN_USERNAME); formData.add("password", ADMIN_PASSWORD); + formData.add("grant_type", "password"); + if (!Strings.isNullOrEmpty(scope)) { + formData.add("scope", scope); + } ClientResponse response = wr.type("application/x-www-form-urlencoded").post(ClientResponse.class, formData); if (response.getStatus() >= 300 ){ diff --git a/scm-webapp/src/test/java/sonia/scm/it/IntegrationTestUtil.java b/scm-webapp/src/test/java/sonia/scm/it/IntegrationTestUtil.java index 3ac16313b9..4e274267e8 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/IntegrationTestUtil.java +++ b/scm-webapp/src/test/java/sonia/scm/it/IntegrationTestUtil.java @@ -110,17 +110,16 @@ public final class IntegrationTestUtil * * @return */ - public static ClientResponse authenticate(Client client, String username, - String password) - { - WebResource wr = client.resource(createResourceUrl("authentication/login").concat("?cookie=true")); + public static ClientResponse authenticate(Client client, String username, String password) { + WebResource wr = client.resource(createResourceUrl("auth/access_token")); MultivaluedMap formData = new MultivaluedMapImpl(); formData.add("username", username); formData.add("password", password); + formData.add("cookie", "true"); + formData.add("grant_type", "password"); - return wr.type("application/x-www-form-urlencoded").post( - ClientResponse.class, formData); + return wr.type("application/x-www-form-urlencoded").post(ClientResponse.class, formData); } /** @@ -294,7 +293,7 @@ public final class IntegrationTestUtil */ public static void logoutClient(Client client) { - WebResource wr = createResource(client, "authentication/logout"); + WebResource wr = createResource(client, "auth/logout"); ClientResponse response = wr.get(ClientResponse.class); assertNotNull(response);