From dd5ecb118db8a344dfb72cfdf203046bf9a85c87 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:43:49 +0900 Subject: [PATCH 01/34] =?UTF-8?q?feat:=20OauthClient=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/entity/OauthClient.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/entity/OauthClient.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/entity/OauthClient.java b/src/main/java/com/dku/council/domain/oauth/model/entity/OauthClient.java new file mode 100644 index 00000000..a6839c45 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/entity/OauthClient.java @@ -0,0 +1,58 @@ +package com.dku.council.domain.oauth.model.entity; + +import com.dku.council.domain.oauth.exception.InvalidOauthClientIdException; +import com.dku.council.domain.oauth.exception.InvalidOauthRedirectUriException; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import static javax.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +@Entity +@Getter +@NoArgsConstructor(access = PROTECTED) +public class OauthClient { + @Id + @GeneratedValue(strategy = IDENTITY) + @Column(name = "oauth_client_id") + private Long id; + private String clientId; + private String applicationName; + private String clientSecret; + private String redirectUri; + + private OauthClient(String clientId, String applicationName, String clientSecret, String redirectUri) { + this.clientId = clientId; + this.applicationName = applicationName; + this.clientSecret = clientSecret; + this.redirectUri = redirectUri; + } + + public static OauthClient of(String clientId, String applicationName, String clientSecret, String redirectUri) { + return new OauthClient(clientId, applicationName, clientSecret, redirectUri); + } + + public void checkClientId(String clientId) { + if (!this.clientId.equals(clientId)) { + throw new InvalidOauthClientIdException(clientId); + } + } + + public void checkClientSecret(String clientSecret) { + if (!this.clientSecret.equals(clientSecret)) { + throw new IllegalArgumentException("Invalid client secret"); + } + } + + public void checkRedirectUri(String redirectUri) { + if (!this.redirectUri.equals(redirectUri)) { + throw new InvalidOauthRedirectUriException(redirectUri); + } + } + +} From f849e7923e994934bea814ce069a8e1254693c51 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:44:30 +0900 Subject: [PATCH 02/34] =?UTF-8?q?feat:=20OauthClient=20JPA=20=EB=A0=88?= =?UTF-8?q?=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/repository/OauthClientRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/repository/OauthClientRepository.java diff --git a/src/main/java/com/dku/council/domain/oauth/repository/OauthClientRepository.java b/src/main/java/com/dku/council/domain/oauth/repository/OauthClientRepository.java new file mode 100644 index 00000000..d4ee3667 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/repository/OauthClientRepository.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.repository; + +import com.dku.council.domain.oauth.model.entity.OauthClient; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface OauthClientRepository extends JpaRepository { + Optional findByClientId(String clientId); +} From ff45a541572f4b45159862f8e20c18c375a87ca0 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:45:34 +0900 Subject: [PATCH 03/34] =?UTF-8?q?feat:=20Oauth=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20Enum=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/entity/OauthResponseType.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/entity/OauthResponseType.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/entity/OauthResponseType.java b/src/main/java/com/dku/council/domain/oauth/model/entity/OauthResponseType.java new file mode 100644 index 00000000..9b5a1b11 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/entity/OauthResponseType.java @@ -0,0 +1,15 @@ +package com.dku.council.domain.oauth.model.entity; + +public enum OauthResponseType { + CODE("code"); + + private final String value; + + OauthResponseType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} From 5295c16f4a7eebcf889a851e4f16d5d1bb7c30f9 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:47:24 +0900 Subject: [PATCH 04/34] =?UTF-8?q?feat:=20redis=20=ED=82=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20oauthInfo=20setting=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/OauthRedisRepository.java | 22 +++++++++++++++++++ .../global/config/redis/RedisKeys.java | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java diff --git a/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java new file mode 100644 index 00000000..dc099b26 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java @@ -0,0 +1,22 @@ +package com.dku.council.domain.oauth.repository; + +import com.dku.council.domain.oauth.model.dto.request.OauthCachePayload; +import com.dku.council.global.base.AbstractKeyValueCacheRepository; +import com.dku.council.global.config.redis.RedisKeys; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.time.Duration; +import java.time.Instant; + +@Repository +public class OauthRedisRepository extends AbstractKeyValueCacheRepository { + protected OauthRedisRepository(StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { + super(redisTemplate, objectMapper, RedisKeys.OAUTH_CODE_KEY); + } + + public void cacheOauth(String clientId, OauthCachePayload cachePayload) { + set(clientId, cachePayload, Instant.now(), Duration.ofMinutes(10)); + } +} diff --git a/src/main/java/com/dku/council/global/config/redis/RedisKeys.java b/src/main/java/com/dku/council/global/config/redis/RedisKeys.java index 86d54da4..2236bf76 100644 --- a/src/main/java/com/dku/council/global/config/redis/RedisKeys.java +++ b/src/main/java/com/dku/council/global/config/redis/RedisKeys.java @@ -23,7 +23,7 @@ public class RedisKeys { public static final String SIGNUP_AUTH_KEY = "signupAuth"; public static final String USER_FIND_AUTH_KEY = "userFindAuth"; public static final String USER_INFO_CACHE_KEY = "userInfo"; - + public static final String OAUTH_CODE_KEY = "oauthCode"; public static String combine(Object key1, Object key2) { return key1 + KEY_DELIMITER + key2; From 60f761d86db4b309694d9ac226084686f4e0432b Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:50:10 +0900 Subject: [PATCH 05/34] =?UTF-8?q?feat:=20OauthCachePayload=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/request/OauthCachePayload.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java new file mode 100644 index 00000000..321577b0 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java @@ -0,0 +1,17 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class OauthCachePayload { + String authCode; + String codeChallenge; + String codeChallengeMethod; + String scope; + + public static OauthCachePayload of(String authCode, String codeChallenge, String codeChallengeMethod, String scope) { + return new OauthCachePayload(authCode, codeChallenge, codeChallengeMethod, scope); + } +} From e6a00f3f06ed18a9bb60f05872bbe0bf9f026bed Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:50:38 +0900 Subject: [PATCH 06/34] =?UTF-8?q?feat:=20OauthRequest=20DTO=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/dto/request/OauthRequest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java new file mode 100644 index 00000000..085e2728 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java @@ -0,0 +1,48 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.Getter; + +@Getter +public class OauthRequest { + private final String codeChallenge; + private String codeChallengeMethod = "S256"; + private final String clientId; + private final String redirectUri; + private final String responseType; + private final String scope; + + private OauthRequest(String codeChallenge, String codeChallengeMethod, String clientId, + String redirectUri, String responseType, String scope) { + this.codeChallenge = codeChallenge; + this.codeChallengeMethod = codeChallengeMethod; + this.clientId = clientId; + this.redirectUri = redirectUri; + this.responseType = responseType; + this.scope = scope; + } + + private OauthRequest(String codeChallenge, String clientId, String redirectUri, String responseType, String scope) { + this.codeChallenge = codeChallenge; + this.clientId = clientId; + this.redirectUri = redirectUri; + this.responseType = responseType; + this.scope = scope; + } + + public static OauthRequest of(String codeChallenge, String codeChallengeMethod, String clientId, + String redirectUri, String responseType, String scope) { + if (codeChallengeMethod == null) { + return OauthRequest.of(codeChallenge, clientId, redirectUri, responseType, scope); + } + return new OauthRequest(codeChallenge, codeChallengeMethod, clientId, redirectUri, responseType, scope); + } + + public static OauthRequest of(String codeChallenge, String clientId, + String redirectUri, String responseType, String scope) { + return new OauthRequest(codeChallenge, clientId, redirectUri, responseType, scope); + } + + public OauthCachePayload toCachePayload(String authCode) { + return OauthCachePayload.of(authCode, codeChallenge, codeChallengeMethod, scope); + } +} From 13e618992b8bf3d31e943aec8c2b5c4afb981d69 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:52:11 +0900 Subject: [PATCH 07/34] =?UTF-8?q?feat:=20OauthClientNotFound=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/exception/OauthClientNotFoundException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/OauthClientNotFoundException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/OauthClientNotFoundException.java b/src/main/java/com/dku/council/domain/oauth/exception/OauthClientNotFoundException.java new file mode 100644 index 00000000..90372416 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/OauthClientNotFoundException.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.exception; + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class OauthClientNotFoundException extends LocalizedMessageException { + public OauthClientNotFoundException() { + super(HttpStatus.NOT_FOUND, "notfound.oauth-client"); + } +} From 771750b05168c117bfb77cafffd92a8d570b3747 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:52:30 +0900 Subject: [PATCH 08/34] =?UTF-8?q?feat:=20InvalidOauthResponseType=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/InvalidOauthResponseTypeException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthResponseTypeException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthResponseTypeException.java b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthResponseTypeException.java new file mode 100644 index 00000000..8a462655 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthResponseTypeException.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.exception; + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class InvalidOauthResponseTypeException extends LocalizedMessageException { + public InvalidOauthResponseTypeException(String responseType) { + super(HttpStatus.BAD_REQUEST, "invalid.oauth-response-type", responseType); + } +} From d7ea820266c5f6d71d6b48a443f7b8201b96277c Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:52:41 +0900 Subject: [PATCH 09/34] =?UTF-8?q?feat:=20InvalidOauthClientId=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/InvalidOauthClientIdException.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthClientIdException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthClientIdException.java b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthClientIdException.java new file mode 100644 index 00000000..e3786760 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthClientIdException.java @@ -0,0 +1,11 @@ +package com.dku.council.domain.oauth.exception; + + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class InvalidOauthClientIdException extends LocalizedMessageException { + public InvalidOauthClientIdException(String clientId) { + super(HttpStatus.BAD_REQUEST, "invalid.oauth-client-id: " + clientId); + } +} From f201ed8a7562842b114e7847097457ba055efd63 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:52:52 +0900 Subject: [PATCH 10/34] =?UTF-8?q?feat:=20InvalidOauthRedirectUri=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/InvalidOauthRedirectUriException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthRedirectUriException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthRedirectUriException.java b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthRedirectUriException.java new file mode 100644 index 00000000..2b6e0944 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/InvalidOauthRedirectUriException.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.exception; + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class InvalidOauthRedirectUriException extends LocalizedMessageException { + public InvalidOauthRedirectUriException(String redirectUri) { + super(HttpStatus.BAD_REQUEST, "invalid.oauth-redirect-uri", redirectUri); + } +} From b570c0adc8590bd6c2d596337c204ebed4e1438a Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:54:03 +0900 Subject: [PATCH 11/34] =?UTF-8?q?feat:=20authorize=20=EB=B0=8F=20redirect?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/service/OauthService.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/service/OauthService.java diff --git a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java new file mode 100644 index 00000000..92314a36 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java @@ -0,0 +1,49 @@ +package com.dku.council.domain.oauth.service; + +import com.dku.council.domain.oauth.exception.InvalidOauthResponseTypeException; +import com.dku.council.domain.oauth.exception.OauthClientNotFoundException; +import com.dku.council.domain.oauth.model.dto.request.OauthCachePayload; +import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import com.dku.council.domain.oauth.model.entity.OauthClient; +import com.dku.council.domain.oauth.model.entity.OauthResponseType; +import com.dku.council.domain.oauth.repository.OauthClientRepository; +import com.dku.council.domain.oauth.repository.OauthRedisRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.UUID; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class OauthService { + private final OauthClientRepository oauthClientRepository; + private final OauthRedisRepository oauthRedisRepository; + + @Transactional + public String authorize(OauthRequest authRequest) { + String clientId = authRequest.getClientId(); + String redirectUri = authRequest.getRedirectUri(); + checkResponseType(authRequest.getResponseType()); + OauthClient oauthClient = oauthClientRepository.findByClientId(clientId) + .orElseThrow(OauthClientNotFoundException::new); + oauthClient.checkClientId(clientId); + oauthClient.checkRedirectUri(redirectUri); + String authCode = UUID.randomUUID().toString(); + OauthCachePayload cachePayload = authRequest.toCachePayload(authCode); + oauthRedisRepository.cacheOauth(clientId, cachePayload); + return UriComponentsBuilder + .fromUriString(oauthClient.getRedirectUri()) + .queryParam("code", authCode) + .toUriString(); + } + + private void checkResponseType(String responseType) { + String type = OauthResponseType.CODE.getValue(); + if (!responseType.equals(type)) { + throw new InvalidOauthResponseTypeException(responseType); + } + } +} From fe468bf683e7ddd85983114e7b35ad0864528344 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:54:11 +0900 Subject: [PATCH 12/34] =?UTF-8?q?feat:=20authorize=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/controller/OauthController.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/controller/OauthController.java diff --git a/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java new file mode 100644 index 00000000..2ebdc530 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java @@ -0,0 +1,31 @@ +package com.dku.council.domain.oauth.controller; + +import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import com.dku.council.domain.oauth.service.OauthService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@RestController +@RequestMapping("/oauth") +@RequiredArgsConstructor +public class OauthController { + private final OauthService oauthService; + + @GetMapping("/authorize") + public void authorize(@RequestParam String codeChallenge, + @RequestParam(required = false) String codeChallengeMethod, + @RequestParam String clientId, + @RequestParam String redirectUri, + @RequestParam String responseType, + @RequestParam String scope, + HttpServletResponse response) throws IOException { + OauthRequest request = OauthRequest.of(codeChallenge, codeChallengeMethod, clientId, + redirectUri, responseType, scope); + String uri = oauthService.authorize(request); + response.sendRedirect(uri); + } + +} From 9c46473e501995c22e4bac2e3e386c08b769a34d Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:54:36 +0900 Subject: [PATCH 13/34] =?UTF-8?q?feat:=20OauthClient=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/entity/OauthClientTest.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/test/java/com/dku/council/domain/oauth/model/entity/OauthClientTest.java diff --git a/src/test/java/com/dku/council/domain/oauth/model/entity/OauthClientTest.java b/src/test/java/com/dku/council/domain/oauth/model/entity/OauthClientTest.java new file mode 100644 index 00000000..404fe27f --- /dev/null +++ b/src/test/java/com/dku/council/domain/oauth/model/entity/OauthClientTest.java @@ -0,0 +1,86 @@ +package com.dku.council.domain.oauth.model.entity; + +import com.dku.council.domain.oauth.exception.InvalidOauthClientIdException; +import com.dku.council.domain.oauth.exception.InvalidOauthRedirectUriException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class OauthClientTest { + + @Test + void testGetClientId() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertEquals("id", oauthClient.getClientId()); + } + + @Test + void testGetClientSecret() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertEquals("cs", oauthClient.getClientSecret()); + } + + @Test + void testGetRedirectUri() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertEquals("url", oauthClient.getRedirectUri()); + } + + @Test + void testStaticOf() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertEquals("id", oauthClient.getClientId()); + assertEquals("tm", oauthClient.getApplicationName()); + assertEquals("cs", oauthClient.getClientSecret()); + assertEquals("url", oauthClient.getRedirectUri()); + } + + @Test + void testCheckClientId() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertThrows(InvalidOauthClientIdException.class, + () -> oauthClient.checkClientId("invalidId"), "invalid.oauth-client-id: invalidId"); + } + + @Test + void testCheckClientSecret() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertThrows(IllegalArgumentException.class, + () -> oauthClient.checkClientSecret("invalidCs"), "Invalid client secret"); + } + + @Test + void testCheckRedirectUri() { + String clientId = "id"; + String applicationName = "tm"; + String clientSecret = "cs"; + String redirectUri = "url"; + OauthClient oauthClient = OauthClient.of(clientId, applicationName, clientSecret, redirectUri); + assertThrows(InvalidOauthRedirectUriException.class, + () -> oauthClient.checkRedirectUri("invalidUrl"), "invalid.oauth-redirect-uri: invalidUrl"); + } +} From 2f58c39a95030810ba749480056a8ab7736a4029 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Sat, 17 Feb 2024 15:55:50 +0900 Subject: [PATCH 14/34] =?UTF-8?q?feat:=20authorize=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/service/OauthServiceTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/java/com/dku/council/domain/oauth/service/OauthServiceTest.java diff --git a/src/test/java/com/dku/council/domain/oauth/service/OauthServiceTest.java b/src/test/java/com/dku/council/domain/oauth/service/OauthServiceTest.java new file mode 100644 index 00000000..bc89ad21 --- /dev/null +++ b/src/test/java/com/dku/council/domain/oauth/service/OauthServiceTest.java @@ -0,0 +1,57 @@ +package com.dku.council.domain.oauth.service; + +import com.dku.council.domain.oauth.exception.InvalidOauthResponseTypeException; +import com.dku.council.domain.oauth.exception.OauthClientNotFoundException; +import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +class OauthServiceTest { + @InjectMocks + private OauthService oauthService; + + @Test + @DisplayName("responseType이 올바르지 않은 경우") + void checkInvalidResponseType() { + // given + String codeChallenge = "codeChallenge"; + String codeChallengeMethod = "S256"; + String clientId = "clientId"; + String redirectUri = "http://localhost:8080/oauth/redirect"; + String responseType = "not_code"; + String scope = "nickname email"; + OauthRequest request = OauthRequest.of(codeChallenge, codeChallengeMethod, clientId, + redirectUri, responseType, scope); + + // when, then + assertThrows(InvalidOauthResponseTypeException.class, () -> { + oauthService.authorize(request); + }, "Invalid.oauth-response-type: not_code"); + } + + @Test + @DisplayName("해당 clientId가 존재하지 않는 경우") + void checkClientIdNotExist() { + // given + String codeChallenge = "codeChallenge"; + String codeChallengeMethod = "S256"; + String clientId = "notExistClientId"; + String redirectUri = "http://localhost:8080/oauth/redirect"; + String responseType = "code"; + String scope = "nickname email"; + OauthRequest request = OauthRequest.of(codeChallenge, codeChallengeMethod, clientId, + redirectUri, responseType, scope); + + // when, then + assertThrows(OauthClientNotFoundException.class, () -> { + oauthService.authorize(request); + }, "notfound.oauth-client: notExistClientId"); + } +} \ No newline at end of file From 8b0bda16b5d4d11264c61b9e886c2c0fd40da1ac Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:49:12 +0900 Subject: [PATCH 15/34] =?UTF-8?q?refactor:=20Oauth=20=EC=BA=90=EC=8B=B1=20?= =?UTF-8?q?=ED=82=A4=20authCode=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/repository/OauthRedisRepository.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java index dc099b26..73566697 100644 --- a/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java +++ b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java @@ -16,7 +16,8 @@ protected OauthRedisRepository(StringRedisTemplate redisTemplate, ObjectMapper o super(redisTemplate, objectMapper, RedisKeys.OAUTH_CODE_KEY); } - public void cacheOauth(String clientId, OauthCachePayload cachePayload) { - set(clientId, cachePayload, Instant.now(), Duration.ofMinutes(10)); + public void cacheOauth(String authCode, OauthCachePayload cachePayload) { + set(authCode, cachePayload, Instant.now(), Duration.ofMinutes(10)); + } } } From 5142c3c2def8c16ca30525e0b17d34146857477d Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:50:02 +0900 Subject: [PATCH 16/34] =?UTF-8?q?refactor:=20OauthRequestDTO=20to=20OauthC?= =?UTF-8?q?acheVO=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../council/domain/oauth/model/dto/request/OauthRequest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java index 085e2728..7e4b24ae 100644 --- a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthRequest.java @@ -41,8 +41,4 @@ public static OauthRequest of(String codeChallenge, String clientId, String redirectUri, String responseType, String scope) { return new OauthRequest(codeChallenge, clientId, redirectUri, responseType, scope); } - - public OauthCachePayload toCachePayload(String authCode) { - return OauthCachePayload.of(authCode, codeChallenge, codeChallengeMethod, scope); - } } From 9a41919a5cb3b8acbddbe530766bd1ffe8f1f37e Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:51:03 +0900 Subject: [PATCH 17/34] =?UTF-8?q?refactor:=20oauth/authorize=20=EC=A4=91?= =?UTF-8?q?=20=EC=BA=90=EC=8B=B1=20=EB=B0=8F=20authCode=EB=B0=98=ED=99=98?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/service/OauthService.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java index 92314a36..311f43e4 100644 --- a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java +++ b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java @@ -22,21 +22,15 @@ public class OauthService { private final OauthClientRepository oauthClientRepository; private final OauthRedisRepository oauthRedisRepository; - @Transactional - public String authorize(OauthRequest authRequest) { - String clientId = authRequest.getClientId(); - String redirectUri = authRequest.getRedirectUri(); - checkResponseType(authRequest.getResponseType()); - OauthClient oauthClient = oauthClientRepository.findByClientId(clientId) - .orElseThrow(OauthClientNotFoundException::new); + public String authorize(OauthRequest oauthRequest) { + String clientId = oauthRequest.getClientId(); + String redirectUri = oauthRequest.getRedirectUri(); + checkResponseType(oauthRequest.getResponseType()); + OauthClient oauthClient = getOauthClient(clientId); oauthClient.checkClientId(clientId); oauthClient.checkRedirectUri(redirectUri); - String authCode = UUID.randomUUID().toString(); - OauthCachePayload cachePayload = authRequest.toCachePayload(authCode); - oauthRedisRepository.cacheOauth(clientId, cachePayload); return UriComponentsBuilder .fromUriString(oauthClient.getRedirectUri()) - .queryParam("code", authCode) .toUriString(); } From 4a03b6ed533dd9f44f5a0acbca44ff3f4c7cd9d3 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:53:01 +0900 Subject: [PATCH 18/34] =?UTF-8?q?feat:=20OauthLoginRequest=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/request/OauthLoginRequest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthLoginRequest.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthLoginRequest.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthLoginRequest.java new file mode 100644 index 00000000..d9233fee --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthLoginRequest.java @@ -0,0 +1,40 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import com.dku.council.domain.user.model.dto.request.RequestLoginDto; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import javax.validation.constraints.NotBlank; + +@Getter +@AllArgsConstructor +public class OauthLoginRequest { + @NotBlank + @Schema(description = "아이디(학번)", example = "12345678") + private final String studentId; + + @NotBlank + @Schema(description = "비밀번호", example = "121212") + private final String password; + + private final String clientId; + + private final String redirectUri; + + private final String codeChallenge; + + private final String codeChallengeMethod; + + private final String scope; + + private final String responseType; + + public RequestLoginDto toLoginInfo() { + return new RequestLoginDto(studentId, password); + } + + public OauthInfo toOauthInfo() { + return OauthInfo.of(clientId, redirectUri, codeChallenge, codeChallengeMethod, scope, responseType); + } +} From 38e35724ca48c57d4edfb3caf748b319e7982263 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:53:11 +0900 Subject: [PATCH 19/34] =?UTF-8?q?feat:=20OauthLoginResponse=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/response/OauthLoginResponse.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/response/OauthLoginResponse.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/response/OauthLoginResponse.java b/src/main/java/com/dku/council/domain/oauth/model/dto/response/OauthLoginResponse.java new file mode 100644 index 00000000..c3280dd5 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/response/OauthLoginResponse.java @@ -0,0 +1,15 @@ +package com.dku.council.domain.oauth.model.dto.response; + +import lombok.Getter; + +@Getter +public class OauthLoginResponse { + private final String authCode; + + private OauthLoginResponse(String authCode) { + this.authCode = authCode; + } + public static OauthLoginResponse from(String authCode) { + return new OauthLoginResponse(authCode); + } +} From 4b2c7cbfa21a208ac2b8d34803e8f2dc0b1c1090 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:53:58 +0900 Subject: [PATCH 20/34] =?UTF-8?q?feat:=20OauthInfo=20VO=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/dto/request/OauthInfo.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthInfo.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthInfo.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthInfo.java new file mode 100644 index 00000000..a1308267 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthInfo.java @@ -0,0 +1,31 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.Getter; + +@Getter +public class OauthInfo { + private final String clientId; + private final String redirectUri; + private final String codeChallenge; + private final String codeChallengeMethod; + private final String scope; + private final String responseType; + + private OauthInfo(String clientId, String redirectUri, String codeChallenge, String codeChallengeMethod, String scope, String responseType) { + this.clientId = clientId; + this.redirectUri = redirectUri; + this.codeChallenge = codeChallenge; + this.codeChallengeMethod = codeChallengeMethod; + this.scope = scope; + this.responseType = responseType; + } + + public static OauthInfo of(String clientId, String redirectUri, String codeChallenge, String codeChallengeMethod, String scope, String responseType) { + return new OauthInfo(clientId, redirectUri, codeChallenge, codeChallengeMethod, scope, responseType); + } + + public OauthCachePayload toCachePayload(Long userId) { + return OauthCachePayload.of(userId, codeChallenge, codeChallengeMethod, scope); + } + +} From 45040a54e7d1b190cc97a6663aa42e23c9e79893 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Wed, 21 Feb 2024 23:55:41 +0900 Subject: [PATCH 21/34] =?UTF-8?q?feat:=20oauth/login=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../council/domain/oauth/controller/OauthController.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java index 2ebdc530..593701a2 100644 --- a/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java +++ b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java @@ -1,8 +1,11 @@ package com.dku.council.domain.oauth.controller; +import com.dku.council.domain.oauth.model.dto.request.OauthLoginRequest; import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import com.dku.council.domain.oauth.model.dto.response.OauthLoginResponse; import com.dku.council.domain.oauth.service.OauthService; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; @@ -28,4 +31,9 @@ public void authorize(@RequestParam String codeChallenge, response.sendRedirect(uri); } + @PostMapping("/login") + public ResponseEntity login(@RequestBody OauthLoginRequest request) throws IOException { + OauthLoginResponse response = oauthService.login(request.toLoginInfo(), request.toOauthInfo()); + return ResponseEntity.ok(response); + } } From 901cda92a65126b93129954bcb7c36f03233a638 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 00:01:37 +0900 Subject: [PATCH 22/34] =?UTF-8?q?feat:=20oauth=20login=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80(=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5=20=EC=8B=9C=20authCode=EB=B0=98=ED=99=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/service/OauthService.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java index 311f43e4..717b9514 100644 --- a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java +++ b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java @@ -8,7 +8,14 @@ import com.dku.council.domain.oauth.model.entity.OauthResponseType; import com.dku.council.domain.oauth.repository.OauthClientRepository; import com.dku.council.domain.oauth.repository.OauthRedisRepository; +import com.dku.council.domain.user.exception.WrongPasswordException; +import com.dku.council.domain.user.model.dto.request.RequestLoginDto; +import com.dku.council.domain.user.model.entity.User; +import com.dku.council.domain.user.repository.UserRepository; +import com.dku.council.domain.user.util.CodeGenerator; +import com.dku.council.global.error.exception.UserNotFoundException; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.util.UriComponentsBuilder; @@ -21,6 +28,8 @@ public class OauthService { private final OauthClientRepository oauthClientRepository; private final OauthRedisRepository oauthRedisRepository; + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; public String authorize(OauthRequest oauthRequest) { String clientId = oauthRequest.getClientId(); @@ -34,6 +43,21 @@ public String authorize(OauthRequest oauthRequest) { .toUriString(); } + @Transactional + public OauthLoginResponse login(RequestLoginDto loginInfo, OauthInfo oauthInfo) { + checkResponseType(oauthInfo.getResponseType()); + User user = userRepository.findByStudentId(loginInfo.getStudentId()) + .orElseThrow(UserNotFoundException::new); + + if (!passwordEncoder.matches(loginInfo.getPassword(), user.getPassword())) { + throw new WrongPasswordException(); + } + String authCode = CodeGenerator.generateUUIDCode(); + Long userId = user.getId(); + OauthCachePayload cachePayload = oauthInfo.toCachePayload(userId); + oauthRedisRepository.cacheOauth(authCode, cachePayload); + return OauthLoginResponse.from(authCode); + } private void checkResponseType(String responseType) { String type = OauthResponseType.CODE.getValue(); if (!responseType.equals(type)) { From f730e3d6ab636da0410dd7b77e759eb94ca75b1a Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:40:18 +0900 Subject: [PATCH 23/34] =?UTF-8?q?refactor:=20OauthCachePayload=20VO=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20codeChall?= =?UTF-8?q?enge=20=EB=8F=99=EB=93=B1=EC=84=B1=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/dto/request/OauthCachePayload.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java index 321577b0..4eaa46e2 100644 --- a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OauthCachePayload.java @@ -1,17 +1,24 @@ package com.dku.council.domain.oauth.model.dto.request; +import com.dku.council.domain.oauth.exception.InvalidCodeChallengeException; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public class OauthCachePayload { - String authCode; + Long userId; String codeChallenge; String codeChallengeMethod; String scope; - public static OauthCachePayload of(String authCode, String codeChallenge, String codeChallengeMethod, String scope) { - return new OauthCachePayload(authCode, codeChallenge, codeChallengeMethod, scope); + public static OauthCachePayload of(Long userId, String codeChallenge, String codeChallengeMethod, String scope) { + return new OauthCachePayload(userId, codeChallenge, codeChallengeMethod, scope); + } + + public void checkCodeChallenge(String codeChallenge) { + if (!this.codeChallenge.equals(codeChallenge)) { + throw new InvalidCodeChallengeException(codeChallenge); + } } } From b328e41841b186544f1dfd6d339b622d1faff32f Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:41:59 +0900 Subject: [PATCH 24/34] =?UTF-8?q?feat:=20OauthClient=20VO=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/dto/request/ClientInfo.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/ClientInfo.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/ClientInfo.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/ClientInfo.java new file mode 100644 index 00000000..c04ad233 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/ClientInfo.java @@ -0,0 +1,20 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.Getter; + +@Getter +public class ClientInfo { + private final String clientId; + private final String clientSecret; + private final String redirectUri; + + private ClientInfo(String clientId, String clientSecret, String redirectUri) { + this.clientId = clientId; + this.clientSecret = clientSecret; + this.redirectUri = redirectUri; + } + + public static ClientInfo of(String clientId, String clientSecret, String redirectUri) { + return new ClientInfo(clientId, clientSecret, redirectUri); + } +} From 1df044581f8256bad7b58482c248193a1981bf2a Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:42:09 +0900 Subject: [PATCH 25/34] =?UTF-8?q?feat:=20OauthTarget=20VO=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/dto/request/OAuthTarget.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/OAuthTarget.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/OAuthTarget.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OAuthTarget.java new file mode 100644 index 00000000..2a95425a --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/OAuthTarget.java @@ -0,0 +1,20 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.Getter; + +@Getter +public class OAuthTarget { + private final String grantType; + private final String code; + private final String codeVerifier; + + private OAuthTarget(String grantType, String code, String codeVerifier) { + this.grantType = grantType; + this.code = code; + this.codeVerifier = codeVerifier; + } + + public static OAuthTarget of(String grantType, String code, String codeVerifier) { + return new OAuthTarget(grantType, code, codeVerifier); + } +} From 71dfdf723fc3db44ed41ae9a02e21c3e5485435b Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:42:23 +0900 Subject: [PATCH 26/34] =?UTF-8?q?feat:=20TokenExchangeRequest=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/TokenExchangeRequest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/request/TokenExchangeRequest.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/request/TokenExchangeRequest.java b/src/main/java/com/dku/council/domain/oauth/model/dto/request/TokenExchangeRequest.java new file mode 100644 index 00000000..d4f17910 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/request/TokenExchangeRequest.java @@ -0,0 +1,36 @@ +package com.dku.council.domain.oauth.model.dto.request; + +import lombok.Getter; + +@Getter +public class TokenExchangeRequest { + String grantType; + String clientId; + String redirectUri; + String clientSecret; + String code; + String codeVerifier; + + private TokenExchangeRequest(String grantType, String clientId, String redirectUri, + String clientSecret, String code, String codeVerifier) { + this.grantType = grantType; + this.clientId = clientId; + this.redirectUri = redirectUri; + this.clientSecret = clientSecret; + this.code = code; + this.codeVerifier = codeVerifier; + } + + public static TokenExchangeRequest of(String grantType, String clientId, String redirectUri, + String clientSecret, String code, String codeVerifier) { + return new TokenExchangeRequest(grantType, clientId, redirectUri, clientSecret, code, codeVerifier); + } + + public ClientInfo toClientInfo() { + return ClientInfo.of(clientId, clientSecret, redirectUri); + } + + public OAuthTarget toAuthTarget() { + return OAuthTarget.of(grantType, code, codeVerifier); + } +} From bb918da89b9bb66b65a27d5fb210be63e6933b4c Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:42:31 +0900 Subject: [PATCH 27/34] =?UTF-8?q?feat:=20TokenExchangeResponse=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/TokenExchangeResponse.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/dto/response/TokenExchangeResponse.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/dto/response/TokenExchangeResponse.java b/src/main/java/com/dku/council/domain/oauth/model/dto/response/TokenExchangeResponse.java new file mode 100644 index 00000000..3ef2a544 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/dto/response/TokenExchangeResponse.java @@ -0,0 +1,21 @@ +package com.dku.council.domain.oauth.model.dto.response; + +import lombok.Getter; + +@Getter +public class TokenExchangeResponse { + private String accessToken; + private String refreshToken; + private final String tokenType = "Bearer"; + private String scope; + + private TokenExchangeResponse(String accessToken, String refreshToken, String scope) { + this.accessToken = accessToken; + this.refreshToken = refreshToken; + this.scope = scope; + } + + public static TokenExchangeResponse of(String accessToken, String refreshToken, String scope) { + return new TokenExchangeResponse(accessToken, refreshToken, scope); + } +} From fb763b78949848e764b8b62ef24e0d0f29bd75b6 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:42:46 +0900 Subject: [PATCH 28/34] =?UTF-8?q?feat:=20Hash=EC=95=8C=EA=B3=A0=EB=A6=AC?= =?UTF-8?q?=EC=A6=98=20enum=20class=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/model/entity/HashAlgorithm.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/model/entity/HashAlgorithm.java diff --git a/src/main/java/com/dku/council/domain/oauth/model/entity/HashAlgorithm.java b/src/main/java/com/dku/council/domain/oauth/model/entity/HashAlgorithm.java new file mode 100644 index 00000000..5fbc7f34 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/model/entity/HashAlgorithm.java @@ -0,0 +1,19 @@ +package com.dku.council.domain.oauth.model.entity; + +import lombok.Getter; + +@Getter +public enum HashAlgorithm { + SHA1("SHA-1", "S1"), + SHA256("SHA-256", "S256"), + SHA512("SHA-512", "S512"); + + private final String algorithm; + private final String shortenedAlgorithm; + + HashAlgorithm(String algorithm, String shortenedAlgorithm) { + this.algorithm = algorithm; + this.shortenedAlgorithm = shortenedAlgorithm; + } + +} From f3bd3cdf9477c19656eb9fbdf32a2b4d3820d9fa Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:43:01 +0900 Subject: [PATCH 29/34] =?UTF-8?q?feat:=20InvalidCodeChallengeException=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/exception/InvalidCodeChallengeException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/InvalidCodeChallengeException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/InvalidCodeChallengeException.java b/src/main/java/com/dku/council/domain/oauth/exception/InvalidCodeChallengeException.java new file mode 100644 index 00000000..8fcf48c3 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/InvalidCodeChallengeException.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.exception; + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class InvalidCodeChallengeException extends LocalizedMessageException { + public InvalidCodeChallengeException(String code) { + super(HttpStatus.BAD_REQUEST, "invalid.code-challenge: " + code); + } +} From f88700a28402cad4d6c1e0ffd7e3dc1e548bc2a4 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:43:10 +0900 Subject: [PATCH 30/34] =?UTF-8?q?feat:=20InvalidGrantTypeException=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/exception/InvalidGrantTypeException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/exception/InvalidGrantTypeException.java diff --git a/src/main/java/com/dku/council/domain/oauth/exception/InvalidGrantTypeException.java b/src/main/java/com/dku/council/domain/oauth/exception/InvalidGrantTypeException.java new file mode 100644 index 00000000..4f1f8c21 --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/exception/InvalidGrantTypeException.java @@ -0,0 +1,10 @@ +package com.dku.council.domain.oauth.exception; + +import com.dku.council.global.error.exception.LocalizedMessageException; +import org.springframework.http.HttpStatus; + +public class InvalidGrantTypeException extends LocalizedMessageException { + public InvalidGrantTypeException(String grantType) { + super(HttpStatus.BAD_REQUEST, "invalid.oauth-grant-type: " + grantType); + } +} From 602a20b0a79cb8e59304847c860c6690680454b4 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:43:57 +0900 Subject: [PATCH 31/34] =?UTF-8?q?feat:=20From=20codeVerifier=20To=20CodeCh?= =?UTF-8?q?allenge=20Converter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/util/CodeChallengeConverter.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/oauth/util/CodeChallengeConverter.java diff --git a/src/main/java/com/dku/council/domain/oauth/util/CodeChallengeConverter.java b/src/main/java/com/dku/council/domain/oauth/util/CodeChallengeConverter.java new file mode 100644 index 00000000..52b1bebb --- /dev/null +++ b/src/main/java/com/dku/council/domain/oauth/util/CodeChallengeConverter.java @@ -0,0 +1,26 @@ +package com.dku.council.domain.oauth.util; + +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +@Component +public class CodeChallengeConverter { + public String convertToCodeChallenge(String code, String codeChallengeMethod) { + byte[] digest = getDigest(code.getBytes(StandardCharsets.UTF_8), codeChallengeMethod); + return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); + } + + private static byte[] getDigest(byte[] input, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + return md.digest(input); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + +} From 707e5a2f84c9939a64fc6ff6c09943b75a8692bb Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:44:45 +0900 Subject: [PATCH 32/34] =?UTF-8?q?feat:=20Redis=20Oauth=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=A0=95=EB=B3=B4=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EA=B8=B0,=20=EC=A7=80=EC=9A=B0=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/repository/OauthRedisRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java index 73566697..67d4db96 100644 --- a/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java +++ b/src/main/java/com/dku/council/domain/oauth/repository/OauthRedisRepository.java @@ -9,6 +9,7 @@ import java.time.Duration; import java.time.Instant; +import java.util.Optional; @Repository public class OauthRedisRepository extends AbstractKeyValueCacheRepository { @@ -19,5 +20,12 @@ protected OauthRedisRepository(StringRedisTemplate redisTemplate, ObjectMapper o public void cacheOauth(String authCode, OauthCachePayload cachePayload) { set(authCode, cachePayload, Instant.now(), Duration.ofMinutes(10)); } + + public Optional getOauth(String authCode) { + return get(authCode, OauthCachePayload.class, Instant.now()); + } + + public void deleteOauth(String authCode) { + remove(authCode); } } From 9871a3b739db115c25b01e1c2ec6ecbf4d8e90b8 Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:45:19 +0900 Subject: [PATCH 33/34] =?UTF-8?q?feat:=20=ED=86=A0=ED=81=B0=EA=B5=90?= =?UTF-8?q?=ED=99=98=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/controller/OauthController.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java index 593701a2..bef178bd 100644 --- a/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java +++ b/src/main/java/com/dku/council/domain/oauth/controller/OauthController.java @@ -2,7 +2,9 @@ import com.dku.council.domain.oauth.model.dto.request.OauthLoginRequest; import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import com.dku.council.domain.oauth.model.dto.request.TokenExchangeRequest; import com.dku.council.domain.oauth.model.dto.response.OauthLoginResponse; +import com.dku.council.domain.oauth.model.dto.response.TokenExchangeResponse; import com.dku.council.domain.oauth.service.OauthService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -36,4 +38,19 @@ public ResponseEntity login(@RequestBody OauthLoginRequest r OauthLoginResponse response = oauthService.login(request.toLoginInfo(), request.toOauthInfo()); return ResponseEntity.ok(response); } + + + @PostMapping("/token") + public ResponseEntity exchangeToken(@RequestParam String grantType, + @RequestParam String clientId, + @RequestParam String redirectUri, + @RequestParam String clientSecret, + @RequestParam String code, + @RequestParam String codeVerifier) { + TokenExchangeRequest request = TokenExchangeRequest.of(grantType, clientId, redirectUri, + clientSecret, code, codeVerifier); + TokenExchangeResponse response = oauthService.exchangeToken(request.toClientInfo(), request.toAuthTarget()); + return ResponseEntity.ok(response); + } + } From 6a3411d059b4e961a73ad023d523f3f7b2ae11aa Mon Sep 17 00:00:00 2001 From: juy4556 Date: Thu, 22 Feb 2024 17:45:42 +0900 Subject: [PATCH 34/34] =?UTF-8?q?feat:=20=ED=86=A0=ED=81=B0=EA=B5=90?= =?UTF-8?q?=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/oauth/service/OauthService.java | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java index 717b9514..481c9f47 100644 --- a/src/main/java/com/dku/council/domain/oauth/service/OauthService.java +++ b/src/main/java/com/dku/council/domain/oauth/service/OauthService.java @@ -1,18 +1,24 @@ package com.dku.council.domain.oauth.service; +import com.dku.council.domain.oauth.exception.InvalidGrantTypeException; import com.dku.council.domain.oauth.exception.InvalidOauthResponseTypeException; import com.dku.council.domain.oauth.exception.OauthClientNotFoundException; -import com.dku.council.domain.oauth.model.dto.request.OauthCachePayload; -import com.dku.council.domain.oauth.model.dto.request.OauthRequest; +import com.dku.council.domain.oauth.model.dto.request.*; +import com.dku.council.domain.oauth.model.dto.response.OauthLoginResponse; +import com.dku.council.domain.oauth.model.dto.response.TokenExchangeResponse; +import com.dku.council.domain.oauth.model.entity.HashAlgorithm; import com.dku.council.domain.oauth.model.entity.OauthClient; import com.dku.council.domain.oauth.model.entity.OauthResponseType; import com.dku.council.domain.oauth.repository.OauthClientRepository; import com.dku.council.domain.oauth.repository.OauthRedisRepository; +import com.dku.council.domain.oauth.util.CodeChallengeConverter; import com.dku.council.domain.user.exception.WrongPasswordException; import com.dku.council.domain.user.model.dto.request.RequestLoginDto; import com.dku.council.domain.user.model.entity.User; import com.dku.council.domain.user.repository.UserRepository; import com.dku.council.domain.user.util.CodeGenerator; +import com.dku.council.global.auth.jwt.AuthenticationToken; +import com.dku.council.global.auth.jwt.JwtProvider; import com.dku.council.global.error.exception.UserNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; @@ -20,7 +26,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.util.UriComponentsBuilder; -import java.util.UUID; +import java.util.Objects; @Service @Transactional(readOnly = true) @@ -30,6 +36,8 @@ public class OauthService { private final OauthRedisRepository oauthRedisRepository; private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + private final CodeChallengeConverter codeChallengeConverter; + private final JwtProvider jwtProvider; public String authorize(OauthRequest oauthRequest) { String clientId = oauthRequest.getClientId(); @@ -58,10 +66,61 @@ public OauthLoginResponse login(RequestLoginDto loginInfo, OauthInfo oauthInfo) oauthRedisRepository.cacheOauth(authCode, cachePayload); return OauthLoginResponse.from(authCode); } + + public TokenExchangeResponse exchangeToken(ClientInfo clientInfo, OAuthTarget target) { + checkGrantType(target.getGrantType()); + OauthClient oauthClient = getOauthClient(clientInfo.getClientId()); + oauthClient.checkClientSecret(clientInfo.getClientSecret()); + oauthClient.checkRedirectUri(clientInfo.getRedirectUri()); + OauthCachePayload payload = getPayload(target); + String codeVerifier = target.getCodeVerifier(); + String codeChallengeMethod = getCodeChallengeMethod(payload.getCodeChallengeMethod()); + checkCodeChallenge(codeVerifier, codeChallengeMethod, payload); + User user = userRepository.findById(payload.getUserId()) + .orElseThrow(UserNotFoundException::new); + AuthenticationToken token = jwtProvider.issue(user); + return TokenExchangeResponse.of(token.getAccessToken(), token.getRefreshToken(), payload.getScope()); + } + + private String getCodeChallengeMethod(String codeChallengeMethod) { + if (Objects.equals(codeChallengeMethod, HashAlgorithm.SHA1.getShortenedAlgorithm())) { + codeChallengeMethod = HashAlgorithm.SHA1.getAlgorithm(); + } + if (Objects.equals(codeChallengeMethod, HashAlgorithm.SHA256.getShortenedAlgorithm())) { + codeChallengeMethod = HashAlgorithm.SHA256.getAlgorithm(); + } + if (Objects.equals(codeChallengeMethod, HashAlgorithm.SHA512.getShortenedAlgorithm())) { + codeChallengeMethod = HashAlgorithm.SHA512.getAlgorithm(); + } + return codeChallengeMethod; + } + + private void checkCodeChallenge(String codeVerifier, String codeChallengeMethod, OauthCachePayload payload) { + String convertedCode = codeChallengeConverter.convertToCodeChallenge(codeVerifier, codeChallengeMethod); + payload.checkCodeChallenge(convertedCode); + } + + private OauthCachePayload getPayload(OAuthTarget target) { + return oauthRedisRepository.getOauth(target.getCode()) + .orElseThrow(OauthClientNotFoundException::new); + } + + private OauthClient getOauthClient(String clientId) { + return oauthClientRepository.findByClientId(clientId) + .orElseThrow(OauthClientNotFoundException::new); + } + private void checkResponseType(String responseType) { String type = OauthResponseType.CODE.getValue(); if (!responseType.equals(type)) { throw new InvalidOauthResponseTypeException(responseType); } } + + private void checkGrantType(String grantType) { + if (!grantType.equals("authorization_code")) { + throw new InvalidGrantTypeException(grantType); + } + } + }