Skip to content

Commit

Permalink
#195 fix token-exchange endpoint request parameter should be in reque…
Browse files Browse the repository at this point in the history
…stBody x-www-form-urlencoded
  • Loading branch information
max402 committed Jun 21, 2024
1 parent 298057c commit 207e0a1
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 92 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/push-with-v-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
GPG_OWNERTRUST: ${{ secrets.GPG_OWNERTRUST }}

- name: Step 4 - Build client
run: ./scripts/build_client.sh

- name: Get the tag name
run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV

Expand Down
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
<spring-boot.version>3.2.5</spring-boot.version>
<keystore-management.version>0.0.11</keystore-management.version>
<shedlock.version>5.3.0</shedlock.version>
<openapi.version>2.4.0</openapi.version>
<swagger-annotations.version>2.2.20</swagger-annotations.version>
<openapi.version>2.5.0</openapi.version>
<swagger-annotations.version>2.2.22</swagger-annotations.version>
<jackson.version>2.15.1</jackson.version>
<jackson-databind.version>2.15.1</jackson-databind.version>
<keycloak.version>22.0.4</keycloak.version>
Expand All @@ -73,8 +73,8 @@
<maven-release-plugin.version>3.0.1</maven-release-plugin.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<buildnumber-maven-plugin.version>3.2.0</buildnumber-maven-plugin.version>
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
<maven-deploy-plugin.version>3.1.2</maven-deploy-plugin.version>
<maven-gpg-plugin.version>3.2.4</maven-gpg-plugin.version>
<maven-javadoc-plugin.version>3.6.0</maven-javadoc-plugin.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.adorsys.sts.secretserver;

import de.adorsys.sts.common.config.TokenResource;
import de.adorsys.sts.token.tokenexchange.TokenExchangeService;
import de.adorsys.sts.token.tokenexchange.server.TokenExchangeController;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -11,4 +12,7 @@
@TokenResource
@RequestMapping("${sts.secret-server.endpoint:/secret-server/token-exchange}")
public class SecretServerRestController extends TokenExchangeController {
public SecretServerRestController(TokenExchangeService tokenExchangeService) {
super(tokenExchangeService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,117 +3,50 @@
import de.adorsys.sts.ResponseUtils;
import de.adorsys.sts.token.InvalidParameterException;
import de.adorsys.sts.token.MissingParameterException;
import de.adorsys.sts.token.api.TokenRequestForm;
import de.adorsys.sts.token.api.TokenResponse;
import de.adorsys.sts.token.tokenexchange.TokenExchangeConstants;
import de.adorsys.sts.token.tokenexchange.TokenExchangeRequest;
import de.adorsys.sts.token.tokenexchange.TokenExchangeService;
import de.adorsys.sts.token.tokenexchange.TokenValidationException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.headers.Header;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestBody;

@Slf4j
@RequiredArgsConstructor
public class TokenExchangeController {

private static final Logger logger = LoggerFactory.getLogger(TokenExchangeController.class);

@Autowired
private TokenExchangeService tokenExchangeService;
private final TokenExchangeService tokenExchangeService;

@PostMapping(consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "Exchange Token", description = "Create an access or refresh token given a valide subject token.", responses = {
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", schema = @Schema(implementation = TokenResponse.class))),
@ApiResponse(responseCode = "400", description = "Bad request", headers = @Header(name = "error", description = "invalid request"))
})
public ResponseEntity<Object> tokenExchange(
@Parameter(
name = "grant_type",
description = "Indicates that a token exchange is being performed.",
required = true,
example = TokenExchangeConstants.TOKEN_EXCHANGE_OAUTH_GRANT_TYPE)
@RequestParam(
value = "grant_type",
defaultValue = TokenExchangeConstants.TOKEN_EXCHANGE_OAUTH_GRANT_TYPE
) String grantType,

@Parameter(
name = "resource",
description = "Indicates the physical location of the target service or resource where the client intends to use the requested security token. This enables the authorization server to apply policy as appropriate for the target, such as determining the type and content of the token to be issued or if and how the token is to be encrypted.",
example = "http://localhost:8080/multibanking-service")
@RequestParam(name = "resource", required = false) String[] resources,

@Parameter(
name = "audience",
description = "The logical name of the target service where the client intends to use the requested security token. This serves a purpose similar to the resource parameter, but with the client providing a logical name rather than a physical location.",
example = "http://localhost:8080/multibanking-service")
@RequestParam(name = "audience", required = false) String[] audiences,

@Parameter(
name = "scope",
description = "A list of space-delimited, case-sensitive strings that allow the client to specify the desired scope of the requested security token in the context of the service or resource where the token will be used.",
example = "user banking")
@RequestParam(name = "scope", required = false) String scope,

@Parameter(
name = "requested_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml.",
required = false,
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
@RequestParam(name = "requested_token_type", required = false) String requestedTokenType,

@Parameter(
name = "subject_token",
description = "A security token that represents the identity of the party on behalf of whom the request is being made. Typically, the subject of this token will be the subject of the security token issued in response to this request.",
required = true,
example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJNYXhNdXN0ZXJtYW4iLCJyb2xlIjoiVVNFUiIsImV4cCI6MTQ5NTM5MTAxM30.mN9eFMnEuYgh_KCULI8Gpm1X49wWaA67Ps1M7EFV0BQ")
@RequestParam("subject_token") String subjectToken,

@Parameter(
name = "subject_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml. This can be urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:refresh_token.",
required = true,
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
@RequestParam(value = "subject_token_type", defaultValue = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE) String subjectTokenType,

@Parameter(
name = "actor_token",
description = "A security token that represents the identity of the acting party. Typically this will be the party that is authorized to use the requested security token and act on behalf of the subject.",
required = false,
example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJNYXhNdXN0ZXJtYW4iLCJyb2xlIjoiVVNFUiIsImV4cCI6MTQ5NTM5MTAxM30.mN9eFMnEuYgh_KCULI8Gpm1X49wWaA67Ps1M7EFV0BQ")
@RequestParam(name = "actor_token", required = false) String actorToken,

@Parameter(
name = "actor_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml. This can be urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:refresh_token.",
required = false,
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
@RequestParam(name = "actor_token_type", required = false) String actorTokenType,
HttpServletRequest servletRequest
) {
if (logger.isTraceEnabled()) logger.trace("POST tokenExchange started...");
public ResponseEntity<Object> tokenExchange(@RequestBody @ModelAttribute TokenRequestForm tokenRequestForm, HttpServletRequest servletRequest) {
if (log.isTraceEnabled()) log.trace("POST tokenExchange started...");

TokenExchangeRequest tokenExchange = TokenExchangeRequest.builder()
.grantType(grantType)
.resources(resources)
.subjectToken(subjectToken)
.subjectTokenType(subjectTokenType)
.actorToken(actorToken)
.actorTokenType(actorTokenType)
.grantType(tokenRequestForm.getGrantType())
.resources(tokenRequestForm.getResources())
.subjectToken(tokenRequestForm.getSubjectToken())
.subjectTokenType(tokenRequestForm.getSubjectTokenType())
.actorToken(tokenRequestForm.getActorToken())
.actorTokenType(tokenRequestForm.getActorTokenType())
.issuer(ResponseUtils.getIssuer(servletRequest))
.scope(scope)
.requestedTokenType(requestedTokenType)
.audiences(audiences)
.scope(tokenRequestForm.getScope())
.requestedTokenType(tokenRequestForm.getRequestedTokenType())
.audiences(tokenRequestForm.getAudiences())
.build();

try {
Expand All @@ -127,7 +60,7 @@ public ResponseEntity<Object> tokenExchange(
ResponseEntity<Object> errorData = ResponseUtils.invalidParam(e.getMessage());
return ResponseEntity.badRequest().body(errorData);
} finally {
if (logger.isTraceEnabled()) logger.trace("POST tokenExchange finished.");
if (log.isTraceEnabled()) log.trace("POST tokenExchange finished.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.adorsys.sts.token.tokenexchange.server;

import de.adorsys.sts.common.config.TokenResource;
import de.adorsys.sts.token.tokenexchange.TokenExchangeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -12,4 +13,8 @@
public class TokenExchangeRestController extends TokenExchangeController {

public static final String DEFAULT_PATH = "/token/token-exchange";

public TokenExchangeRestController(TokenExchangeService tokenExchangeService) {
super(tokenExchangeService);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package de.adorsys.sts.token.api;

import de.adorsys.sts.token.tokenexchange.TokenExchangeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.beans.ConstructorProperties;

@Getter
@AllArgsConstructor(onConstructor_ = @ConstructorProperties({"grant_type", "resource", "audience", "scope", "requested_token_type", "subject_token", "subject_token_type", "actor_token", "actor_token_type"}))
@Schema(description = "Carries request form properties of a token-exchange request",
requiredProperties = {"grant_type", "subject_token", "subject_token_type"})
public class TokenRequestForm {

@Schema(name = "grant_type",
description = "Indicates that a token exchange is being performed.",
example = TokenExchangeConstants.TOKEN_EXCHANGE_OAUTH_GRANT_TYPE)
private String grantType;

@Schema(name = "resource",
description = "Indicates the physical location of the target service or resource where the client intends to use the requested security token. This enables the authorization server to apply policy as appropriate for the target, such as determining the type and content of the token to be issued or if and how the token is to be encrypted.",
example = "http://localhost:8080/multibanking-service")
private String[] resources;

@Schema(name = "audience",
description = "The logical name of the target service where the client intends to use the requested security token. This serves a purpose similar to the resource parameter, but with the client providing a logical name rather than a physical location.",
example = "http://localhost:8080/multibanking-service")
private String[] audiences;

@Schema(name = "scope",
description = "A list of space-delimited, case-sensitive strings that allow the client to specify the desired scope of the requested security token in the context of the service or resource where the token will be used.",
example = "user banking")
private String scope;

@Schema(name = "requested_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml.",
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
private String requestedTokenType;

@Schema(name = "subject_token",
description = "A security token that represents the identity of the party on behalf of whom the request is being made. Typically, the subject of this token will be the subject of the security token issued in response to this request.",
example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJNYXhNdXN0ZXJtYW4iLCJyb2xlIjoiVVNFUiIsImV4cCI6MTQ5NTM5MTAxM30.mN9eFMnEuYgh_KCULI8Gpm1X49wWaA67Ps1M7EFV0BQ")
private String subjectToken;

@Schema(name = "subject_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml. This can be urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:refresh_token.",
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
private String subjectTokenType;

@Schema(name = "actor_token",
description = "A security token that represents the identity of the acting party. Typically this will be the party that is authorized to use the requested security token and act on behalf of the subject.",
example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJNYXhNdXN0ZXJtYW4iLCJyb2xlIjoiVVNFUiIsImV4cCI6MTQ5NTM5MTAxM30.mN9eFMnEuYgh_KCULI8Gpm1X49wWaA67Ps1M7EFV0BQ")
private String actorToken;

@Schema(name = "actor_token_type",
description = "An identifier for the type of the requested security token. If the requested type is unspecified, the issued token type is at the discretion of the authorization server and may be dictated by knowledge of the requirements of the service or resource indicated by the resource or audience parameter. This can be urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:saml. This can be urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:refresh_token.",
example = TokenExchangeConstants.JWT_OAUTH_TOKEN_TYPE)
private String actorTokenType;
}

0 comments on commit 207e0a1

Please sign in to comment.