From 02a9b09f9347150fcddbb39d0db9e469bf46bf21 Mon Sep 17 00:00:00 2001 From: Filip Hanik Date: Tue, 19 Apr 2016 13:39:23 -0600 Subject: [PATCH] Add token_format as a parameter to the token retrieval https://www.pivotaltracker.com/story/show/117841495 [#117841495] --- .../identity/uaa/login/TokenEndpointDocs.java | 101 ++++++++++-------- .../identity/uaa/test/SnippetUtils.java | 38 +++++-- 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/TokenEndpointDocs.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/TokenEndpointDocs.java index d643b9b9067..04bbe7b908c 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/TokenEndpointDocs.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/TokenEndpointDocs.java @@ -5,9 +5,11 @@ import org.cloudfoundry.identity.uaa.mock.InjectedMockContextTest; import org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils; import org.cloudfoundry.identity.uaa.oauth.token.CompositeAccessToken; +import org.cloudfoundry.identity.uaa.oauth.token.TokenConstants; import org.cloudfoundry.identity.uaa.scim.ScimUser; import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning; import org.cloudfoundry.identity.uaa.scim.jdbc.JdbcScimUserProvisioning; +import org.cloudfoundry.identity.uaa.test.SnippetUtils; import org.cloudfoundry.identity.uaa.test.TestClient; import org.cloudfoundry.identity.uaa.user.UaaAuthority; import org.cloudfoundry.identity.uaa.util.JsonUtils; @@ -16,7 +18,6 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; import org.springframework.restdocs.request.ParameterDescriptor; -import org.springframework.restdocs.snippet.Attributes; import org.springframework.restdocs.snippet.Snippet; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; @@ -31,6 +32,7 @@ import java.util.Arrays; import static org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils.utils; +import static org.cloudfoundry.identity.uaa.test.SnippetUtils.parameterWithName; import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; @@ -42,9 +44,7 @@ import static org.springframework.restdocs.payload.JsonFieldType.STRING; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; -import static org.springframework.restdocs.snippet.Attributes.key; import static org.springframework.security.oauth2.common.util.OAuth2Utils.CLIENT_ID; import static org.springframework.security.oauth2.common.util.OAuth2Utils.GRANT_TYPE; import static org.springframework.security.oauth2.common.util.OAuth2Utils.REDIRECT_URI; @@ -55,13 +55,11 @@ public class TokenEndpointDocs extends InjectedMockContextTest { - private final Attributes.AttributeBuilder type = key("type"); - private final Attributes.AttributeBuilder constraints = key("constraints"); - - private final ParameterDescriptor grantTypeParameter = parameterWithName(GRANT_TYPE).attributes(constraints.value("Required"), type.value(STRING)); - private final ParameterDescriptor responseTypeParameter = parameterWithName(RESPONSE_TYPE).description("the type of token that should be issued.").attributes(constraints.value("Required"), type.value(STRING)); - private final ParameterDescriptor clientIdParameter = parameterWithName(CLIENT_ID).description("a unique string representing the registration information provided by the client").attributes(constraints.value("Required"), type.value(STRING)); - private final ParameterDescriptor clientSecretParameter = parameterWithName("client_secret").description("the secret passphrase configured for the OAuth client").attributes(constraints.value("Required"), type.value(STRING)); + private final ParameterDescriptor grantTypeParameter = parameterWithName(GRANT_TYPE).required().type(STRING).description("OAuth 2 grant type"); + private final ParameterDescriptor responseTypeParameter = parameterWithName(RESPONSE_TYPE).required().type(STRING).description("the type of token that should be issued."); + private final ParameterDescriptor clientIdParameter = parameterWithName(CLIENT_ID).required().type(STRING).description("a unique string representing the registration information provided by the client"); + private final ParameterDescriptor clientSecretParameter = parameterWithName("client_secret").required().type(STRING).description("the secret passphrase configured for the OAuth client"); + private final ParameterDescriptor opaqueFormatParameter = parameterWithName(TokenConstants.REQUEST_TOKEN_FORMAT).optional(null).type(STRING).description("Can be set to '"+TokenConstants.OPAQUE+"' to retrieve an opaque and revocable token."); private ScimUser user; @@ -101,15 +99,17 @@ public void getTokenUsingAuthCodeGrant() throws Exception { .param(GRANT_TYPE, "authorization_code") .param(RESPONSE_TYPE, "token") .param("code", code) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(REDIRECT_URI, redirect); Snippet requestParameters = requestParameters( responseTypeParameter, clientIdParameter, - parameterWithName(REDIRECT_URI).description("redirection URI to which the authorization server will send the user-agent back once access is granted (or denied)").attributes(constraints.value("Required if provided on authorization request"), type.value(STRING)), - parameterWithName("code").description("the authorization code, obtained from /oauth/authorize, issued for the user").attributes(constraints.value("Required"), type.value(STRING)), + parameterWithName(REDIRECT_URI).description("redirection URI to which the authorization server will send the user-agent back once access is granted (or denied)").attributes(SnippetUtils.constraints.value("Required if provided on authorization request"), SnippetUtils.type.value(STRING)), + parameterWithName("code").description("the authorization code, obtained from /oauth/authorize, issued for the user").attributes(SnippetUtils.constraints.value("Required"), SnippetUtils.type.value(STRING)), grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `authorization_code`"), - clientSecretParameter + clientSecretParameter, + opaqueFormatParameter ); Snippet responseFields = responseFields( @@ -134,13 +134,15 @@ public void getTokenUsingClientCredentialGrant() throws Exception { .param(CLIENT_ID, "login") .param("client_secret", "loginsecret") .param(GRANT_TYPE, "client_credentials") + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(RESPONSE_TYPE, "token"); Snippet requestParameters = requestParameters( responseTypeParameter, clientIdParameter, grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `client_credentials`"), - clientSecretParameter + clientSecretParameter, + opaqueFormatParameter ); Snippet responseFields = responseFields( @@ -160,15 +162,17 @@ public void getTokenUsingClientCredentialGrantWithAuthorizationHeader() throws E String clientAuthorization = new String(Base64.encodeBase64("login:loginsecret".getBytes())); MockHttpServletRequestBuilder postForToken = post("/oauth/token") - .accept(APPLICATION_JSON) - .contentType(APPLICATION_FORM_URLENCODED) - .param(GRANT_TYPE, "client_credentials") - .param(RESPONSE_TYPE, "token") - .header("Authorization", "Basic " + clientAuthorization); + .accept(APPLICATION_JSON) + .contentType(APPLICATION_FORM_URLENCODED) + .param(GRANT_TYPE, "client_credentials") + .param(RESPONSE_TYPE, "token") + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) + .header("Authorization", "Basic " + clientAuthorization); Snippet requestParameters = requestParameters( responseTypeParameter, - grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `client_credentials`") + grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `client_credentials`"), + opaqueFormatParameter ); Snippet requestHeaders = requestHeaders(headerWithName("Authorization").description("Base64 encoded client details in the format: `Basic client_id:client_secret`")); @@ -196,6 +200,7 @@ public void getTokenUsingPasswordGrant() throws Exception { .param(GRANT_TYPE, "password") .param("username", user.getUserName()) .param("password", user.getPassword()) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(RESPONSE_TYPE, "token"); Snippet requestParameters = requestParameters( @@ -203,8 +208,9 @@ public void getTokenUsingPasswordGrant() throws Exception { clientIdParameter, grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `password`"), clientSecretParameter, - parameterWithName("username").description("the username for the user trying to get a token").attributes(constraints.value("Required"), type.value(STRING)), - parameterWithName("password").description("the password for the user trying to get a token").attributes(constraints.value("Required"), type.value(STRING)) + parameterWithName("username").required().type(STRING).description("the username for the user trying to get a token"), + parameterWithName("password").required().type(STRING).description("the password for the user trying to get a token"), + opaqueFormatParameter ); Snippet responseFields = responseFields( @@ -231,13 +237,15 @@ public void getTokenWithClientAuthInHeader() throws Exception { .param(GRANT_TYPE, "password") .param("username", user.getUserName()) .param("password", user.getPassword()) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(RESPONSE_TYPE, "token"); Snippet requestParameters = requestParameters( responseTypeParameter, grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `password`"), - parameterWithName("username").description("the username for the user trying to get a token").attributes(constraints.value("Required"), type.value(STRING)), - parameterWithName("password").description("the password for the user trying to get a token").attributes(constraints.value("Required"), type.value(STRING)) + parameterWithName("username").required().type(STRING).description("the username for the user trying to get a token"), + parameterWithName("password").required().type(STRING).description("the password for the user trying to get a token"), + opaqueFormatParameter ); Snippet requestHeaders = requestHeaders(headerWithName("Authorization").description("Base64 encoded client details in the format: `Basic client_id:client_secret`")); @@ -286,12 +294,14 @@ public void getTokenUsingPasscode() throws Exception { .header("Authorization", "Basic " + clientAuthorization) .param(GRANT_TYPE, "password") .param("passcode", passcode) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(RESPONSE_TYPE, "token"); Snippet requestParameters = requestParameters( responseTypeParameter, grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `password`"), - parameterWithName("passcode").description("the one-time passcode for the user which can be retrieved by going to `/passcode`").attributes(constraints.value("Required"), type.value(STRING)) + parameterWithName("passcode").required().type(STRING).description("the one-time passcode for the user which can be retrieved by going to `/passcode`"), + opaqueFormatParameter ); Snippet responseFields = responseFields( @@ -313,31 +323,34 @@ public void getTokenUsingPasscode() throws Exception { public void refreshToken() throws Exception { createUser(); MockHttpServletRequestBuilder postForToken = post("/oauth/token") - .accept(APPLICATION_JSON) - .contentType(APPLICATION_FORM_URLENCODED) - .param(CLIENT_ID, "app") - .param("client_secret", "appclientsecret") - .param(GRANT_TYPE, "password") - .param("username", user.getUserName()) - .param("password", user.getPassword()) - .param(RESPONSE_TYPE, "token"); + .accept(APPLICATION_JSON) + .contentType(APPLICATION_FORM_URLENCODED) + .param(CLIENT_ID, "app") + .param("client_secret", "appclientsecret") + .param(GRANT_TYPE, "password") + .param("username", user.getUserName()) + .param("password", user.getPassword()) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) + .param(RESPONSE_TYPE, "token"); MvcResult mvcResult = getMockMvc().perform(postForToken).andExpect(status().isOk()).andReturn(); OAuth2RefreshToken refreshToken = JsonUtils.readValue(mvcResult.getResponse().getContentAsString(), CompositeAccessToken.class).getRefreshToken(); MockHttpServletRequestBuilder postForRefreshToken = post("/oauth/token") - .accept(APPLICATION_JSON) - .contentType(APPLICATION_FORM_URLENCODED) - .param(CLIENT_ID, "app") - .param("client_secret", "appclientsecret") - .param(GRANT_TYPE, "refresh_token") - .param("refresh_token", refreshToken.getValue()); + .accept(APPLICATION_JSON) + .contentType(APPLICATION_FORM_URLENCODED) + .param(CLIENT_ID, "app") + .param("client_secret", "appclientsecret") + .param(GRANT_TYPE, "refresh_token") + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) + .param("refresh_token", refreshToken.getValue()); Snippet requestParameters = requestParameters( grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `refresh_token`"), clientIdParameter, clientSecretParameter, - parameterWithName("refresh_token").description("the refresh_token that was returned along with the access token.").attributes(type.value(STRING), constraints.value("Required")) + parameterWithName("refresh_token").required().type(STRING).description("the refresh_token that was returned along with the access token."), + opaqueFormatParameter ); Snippet responseFields = responseFields( @@ -401,15 +414,17 @@ public void getIdTokenUsingAuthCodeGrant() throws Exception { .param(GRANT_TYPE, "authorization_code") .param(RESPONSE_TYPE, "id_token") .param("code", code) + .param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.OPAQUE) .param(REDIRECT_URI, redirect); Snippet requestParameters = requestParameters( responseTypeParameter, clientIdParameter, - parameterWithName(REDIRECT_URI).description("redirection URI to which the authorization server will send the user-agent back once access is granted (or denied)").attributes(constraints.value("Required if provided on authorization request"), type.value(STRING)), - parameterWithName("code").description("the authorization code, obtained from /oauth/authorize, issued for the user").attributes(constraints.value("Required"), type.value(STRING)), + parameterWithName(REDIRECT_URI).type(STRING).description("redirection URI to which the authorization server will send the user-agent back once access is granted (or denied)").attributes(SnippetUtils.constraints.value("Required if provided on authorization request")), + parameterWithName("code").required().type(STRING).description("the authorization code, obtained from /oauth/authorize, issued for the user"), grantTypeParameter.description("the type of authentication being used to obtain the token, in this case `authorization_code`"), - clientSecretParameter + clientSecretParameter, + opaqueFormatParameter ); Snippet responseFields = responseFields( diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/SnippetUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/SnippetUtils.java index 38060cd5e94..483246aaae0 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/SnippetUtils.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/SnippetUtils.java @@ -1,12 +1,20 @@ package org.cloudfoundry.identity.uaa.test; import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.restdocs.request.ParameterDescriptor; import org.springframework.restdocs.snippet.Attributes; import static org.springframework.restdocs.snippet.Attributes.key; public final class SnippetUtils { + + public static final Attributes.AttributeBuilder type = key("type"); + public static final Attributes.AttributeBuilder constraints = key("constraints"); + public static final Attributes.AttributeBuilder defaultvalue = key("default"); + public static final String REQUIRED = "Required"; + public static final String OPTIONAL = "Optional"; + private SnippetUtils() {} public static ConstrainableParameter parameterWithName(String name) { @@ -22,17 +30,22 @@ private ConstrainableParameter(String name) { super(name); } - public ParameterDescriptor required() { - return attributes(key("constraints").value("Required")); + public ConstrainableParameter required() { + return (ConstrainableParameter)attributes(constraints.value(REQUIRED)); } - public ParameterDescriptor optional(Object defaultValue) { + public ConstrainableParameter optional(Object defaultValue) { if(defaultValue == null) { defaultValue = ""; } - Attributes.Attribute[] attrs = new Attributes.Attribute[] { key("constraints").value("Optional"), key("default").value(defaultValue) }; - return attributes(attrs); + Attributes.Attribute[] attrs = new Attributes.Attribute[] { constraints.value(OPTIONAL), defaultvalue.value(defaultValue) }; + return (ConstrainableParameter)attributes(attrs); + } + + public ConstrainableParameter type(JsonFieldType fieldType) { + return (ConstrainableParameter)attributes(type.value(fieldType)); } + } @@ -41,16 +54,21 @@ private ConstrainableField(String name) { super(name); } - public FieldDescriptor required() { - return attributes(key("constraints").value("Required")); + public ConstrainableField required() { + return (ConstrainableField)attributes(constraints.value(REQUIRED)); } - public FieldDescriptor optional(Object defaultValue) { + public ConstrainableField optional(Object defaultValue) { + super.optional(); if(defaultValue == null) { defaultValue = ""; } - Attributes.Attribute[] attrs = new Attributes.Attribute[] { key("constraints").value("Optional"), key("default").value(defaultValue) }; - return attributes(attrs); + Attributes.Attribute[] attrs = new Attributes.Attribute[] {constraints.value(OPTIONAL), defaultvalue.value(defaultValue) }; + return (ConstrainableField)attributes(attrs); + } + public ConstrainableField type(JsonFieldType fieldType) { + return (ConstrainableField)attributes(type.value(fieldType)); } + } }