diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/auth/helper/OauthOidcHelper.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/auth/helper/OauthOidcHelper.java new file mode 100644 index 000000000..9ed00f006 --- /dev/null +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/auth/helper/OauthOidcHelper.java @@ -0,0 +1,41 @@ +package kr.co.pennyway.api.apis.auth.helper; + +import kr.co.pennyway.common.annotation.Helper; +import kr.co.pennyway.infra.common.oidc.OauthOidcProvider; +import kr.co.pennyway.infra.common.oidc.OidcDecodePayload; +import kr.co.pennyway.infra.common.oidc.OidcPublicKey; +import kr.co.pennyway.infra.common.oidc.OidcPublicKeyResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Helper +@RequiredArgsConstructor +@Slf4j +public class OauthOidcHelper { + private final OauthOidcProvider oauthOIDCProvider; + + /** + * ID Token의 payload를 추출하는 메서드
+ * OAuth 2.0 spec에 따라 ID Token의 유효성 검사 수행
+ * + * @param token : idToken + * @param iss : ID Token을 발급한 provider의 URL + * @param aud : ID Token이 발급된 앱의 앱 키 + * @param nonce : 인증 서버 로그인 요청 시 전달한 임의의 문자열 + * @param response : 공개키 목록 + * @return OIDCDecodePayload : ID Token의 payload + */ + public OidcDecodePayload getPayloadFromIdToken(String token, String iss, String aud, String nonce, OidcPublicKeyResponse response) { + String kid = getKidFromUnsignedIdToken(token, iss, aud, nonce); + + OidcPublicKey key = response.getKeys().stream() + .filter(k -> k.kid().equals(kid)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No matching key found")); + return oauthOIDCProvider.getOIDCTokenBody(token, key.n(), key.e()); + } + + private String getKidFromUnsignedIdToken(String token, String iss, String aud, String nonce) { + return oauthOIDCProvider.getKidFromUnsignedTokenHeader(token, iss, aud, nonce); + } +} diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/config/InfraConfig.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/config/InfraConfig.java new file mode 100644 index 000000000..e62ecea67 --- /dev/null +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/config/InfraConfig.java @@ -0,0 +1,18 @@ +package kr.co.pennyway.api.config; + +import kr.co.pennyway.infra.common.properties.AppleOidcProperties; +import kr.co.pennyway.infra.common.properties.GoogleOidcProperties; +import kr.co.pennyway.infra.common.properties.KakaoOidcProperties; +import kr.co.pennyway.infra.common.properties.ServerProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties({ + ServerProperties.class, + AppleOidcProperties.class, + GoogleOidcProperties.class, + KakaoOidcProperties.class +}) +public class InfraConfig { +} diff --git a/pennyway-common/src/main/java/kr/co/pennyway/common/util/MapUtils.java b/pennyway-common/src/main/java/kr/co/pennyway/common/util/MapUtils.java new file mode 100644 index 000000000..773e6dd2a --- /dev/null +++ b/pennyway-common/src/main/java/kr/co/pennyway/common/util/MapUtils.java @@ -0,0 +1,20 @@ +package kr.co.pennyway.common.util; + +import java.util.Map; + +/** + * Map 관련 유틸리티 클래스 + * + * @author YANG JAESEO + */ +public class MapUtils { + /** + * key에 해당하는 값을 반환하고, key가 없을 경우 defaultValue를 반환한다. + */ + public static V getObject(Map map, K key, V defaultValue) { + if (map == null || key == null) { + return defaultValue; + } + return map.getOrDefault(key, defaultValue); + } +} \ No newline at end of file diff --git a/pennyway-infra/build.gradle b/pennyway-infra/build.gradle index f2e1c0b01..8631172c7 100644 --- a/pennyway-infra/build.gradle +++ b/pennyway-infra/build.gradle @@ -1,5 +1,5 @@ -bootJar {enabled = false} -jar {enabled = true} +bootJar { enabled = false } +jar { enabled = true } dependencies { implementation project(':pennyway-common') @@ -11,4 +11,9 @@ dependencies { /* redis */ api 'org.springframework.boot:spring-boot-starter-data-redis' + + /* feign */ + implementation platform("org.springframework.cloud:spring-cloud-dependencies:2023.0.1") + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.1' + implementation 'io.github.openfeign:feign-okhttp:13.2' } diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/PennywayInfraApplication.java b/pennyway-infra/src/main/java/kr/co/pennyway/PennywayInfraApplication.java deleted file mode 100644 index 0bc66b4bb..000000000 --- a/pennyway-infra/src/main/java/kr/co/pennyway/PennywayInfraApplication.java +++ /dev/null @@ -1,5 +0,0 @@ -package kr.co.pennyway; - -public class PennywayInfraApplication { - -} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/PennywayInfraApplication.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/PennywayInfraApplication.java new file mode 100644 index 000000000..b4f57535d --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/PennywayInfraApplication.java @@ -0,0 +1,8 @@ +package kr.co.pennyway.infra; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PennywayInfraApplication { + +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/apple/oidc/AppleOidcClient.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/apple/oidc/AppleOidcClient.java new file mode 100644 index 000000000..6c7078132 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/apple/oidc/AppleOidcClient.java @@ -0,0 +1,22 @@ +package kr.co.pennyway.infra.client.apple.oidc; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClient; +import kr.co.pennyway.infra.common.oidc.OidcPublicKeyResponse; +import kr.co.pennyway.infra.config.DefaultFeignConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +@FeignClient( + name = "AppleOauthClient", + url = "${oauth2.client.provider.apple.jwks-uri}", + configuration = DefaultFeignConfig.class, + qualifiers = "appleOauthClient", + primary = false +) +public interface AppleOidcClient extends OauthOidcClient { + @Override + @Cacheable(value = "AppleOauth", cacheManager = "oidcCacheManager") + @GetMapping("/auth/keys") + OidcPublicKeyResponse getOIDCPublicKey(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/google/oidc/GoogleOidcClient.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/google/oidc/GoogleOidcClient.java new file mode 100644 index 000000000..297fdea98 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/google/oidc/GoogleOidcClient.java @@ -0,0 +1,22 @@ +package kr.co.pennyway.infra.client.google.oidc; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClient; +import kr.co.pennyway.infra.common.oidc.OidcPublicKeyResponse; +import kr.co.pennyway.infra.config.DefaultFeignConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +@FeignClient( + name = "GoogleOauthClient", + url = "${oauth2.client.provider.google.jwks-uri}", + configuration = DefaultFeignConfig.class, + qualifiers = "googleOauthClient", + primary = false +) +public interface GoogleOidcClient extends OauthOidcClient { + @Override + @Cacheable(value = "GoogleOauth", cacheManager = "oidcCacheManager") + @GetMapping("/oauth2/v3/certs") + OidcPublicKeyResponse getOIDCPublicKey(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/kakao/oidc/KakaoOidcClient.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/kakao/oidc/KakaoOidcClient.java new file mode 100644 index 000000000..b9603d3bd --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/client/kakao/oidc/KakaoOidcClient.java @@ -0,0 +1,21 @@ +package kr.co.pennyway.infra.client.kakao.oidc; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClient; +import kr.co.pennyway.infra.common.oidc.OidcPublicKeyResponse; +import kr.co.pennyway.infra.config.DefaultFeignConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +@FeignClient( + name = "KakaoOauthClient", + url = "${oauth2.client.provider.kakao.jwks-uri}", + configuration = DefaultFeignConfig.class, + qualifiers = "kakaoOauthClient" +) +public interface KakaoOidcClient extends OauthOidcClient { + @Override + @Cacheable(value = "KakaoOauth", cacheManager = "oidcCacheManager") + @GetMapping("/.well-known/jwks.json") + OidcPublicKeyResponse getOIDCPublicKey(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/EnablePennywayInfraConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/EnablePennywayInfraConfig.java new file mode 100644 index 000000000..ce58cee3f --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/EnablePennywayInfraConfig.java @@ -0,0 +1,15 @@ +package kr.co.pennyway.infra.common.importer; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Import(PennywayInfraConfigImportSelector.class) +public @interface EnablePennywayInfraConfig { + PennywayInfraConfigGroup[] value(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfig.java new file mode 100644 index 000000000..8a7398e5a --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfig.java @@ -0,0 +1,7 @@ +package kr.co.pennyway.infra.common.importer; + +/** + * Pennyway Infra의 Configurations를 나타내는 Marker Interface + */ +public interface PennywayInfraConfig { +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigGroup.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigGroup.java new file mode 100644 index 000000000..44cd79d98 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigGroup.java @@ -0,0 +1,12 @@ +package kr.co.pennyway.infra.common.importer; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PennywayInfraConfigGroup { + ; + + private final Class configClass; +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigImportSelector.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigImportSelector.java new file mode 100644 index 000000000..05e9cc0cb --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/importer/PennywayInfraConfigImportSelector.java @@ -0,0 +1,25 @@ +package kr.co.pennyway.infra.common.importer; + +import kr.co.pennyway.common.util.MapUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.annotation.DeferredImportSelector; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.lang.NonNull; + +import java.util.Arrays; +import java.util.Map; + +public class PennywayInfraConfigImportSelector implements DeferredImportSelector { + @NotNull + @Override + public String[] selectImports(@NonNull AnnotationMetadata metadata) { + return Arrays.stream(getGroups(metadata)) + .map(v -> v.getConfigClass().getName()) + .toArray(String[]::new); + } + + private PennywayInfraConfigGroup[] getGroups(AnnotationMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes(EnablePennywayInfraConfig.class.getName()); + return (PennywayInfraConfigGroup[]) MapUtils.getObject(attributes, "value", new PennywayInfraConfigGroup[]{}); + } +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClient.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClient.java new file mode 100644 index 000000000..0c4d217a1 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClient.java @@ -0,0 +1,5 @@ +package kr.co.pennyway.infra.common.oidc; + +public interface OauthOidcClient { + OidcPublicKeyResponse getOIDCPublicKey(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClientProperties.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClientProperties.java new file mode 100644 index 000000000..8b03875a6 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcClientProperties.java @@ -0,0 +1,7 @@ +package kr.co.pennyway.infra.common.oidc; + +public interface OauthOidcClientProperties { + String getJwksUri(); + + String getSecret(); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProvider.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProvider.java new file mode 100644 index 000000000..57bd3938f --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProvider.java @@ -0,0 +1,24 @@ +package kr.co.pennyway.infra.common.oidc; + +public interface OauthOidcProvider { + /** + * ID Token의 header에서 kid를 추출하는 메서드 + * + * @param token : idToken + * @param iss : ID Token을 발급한 OAuth 2.0 제공자의 URL + * @param aud : ID Token이 발급된 앱의 앱 키 + * @param nonce : 인증 서버 로그인 요청 시 전달한 임의의 문자열 + * @return kid : ID Token의 서명에 사용된 공개키의 ID + */ + String getKidFromUnsignedTokenHeader(String token, String iss, String aud, String nonce); + + /** + * ID Token의 payload를 추출하는 메서드 + * + * @param token : idToken + * @param modulus : 공개키 모듈(n) + * @param exponent : 공개키 지수(e) + * @return OIDCDecodePayload : ID Token의 payload + */ + OidcDecodePayload getOIDCTokenBody(String token, String modulus, String exponent); +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProviderImpl.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProviderImpl.java new file mode 100644 index 000000000..2010d14b2 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OauthOidcProviderImpl.java @@ -0,0 +1,105 @@ +package kr.co.pennyway.infra.common.oidc; + +import io.jsonwebtoken.*; +import kr.co.pennyway.infra.common.exception.JwtErrorCode; +import kr.co.pennyway.infra.common.exception.JwtErrorException; +import kr.co.pennyway.infra.common.util.JwtErrorCodeUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; + +@Slf4j +@Component +public class OauthOidcProviderImpl implements OauthOidcProvider { + private static final String KID = "kid"; + private static final String RSA = "RSA"; + + @Override + public String getKidFromUnsignedTokenHeader(String token, String iss, String aud, String nonce) { + return (String) getUnsignedTokenClaims(token, iss, aud, nonce).getHeader().get(KID); + } + + @Override + public OidcDecodePayload getOIDCTokenBody(String token, String modulus, String exponent) { + Claims body = getOIDCTokenJws(token, modulus, exponent).getPayload(); + String aud = body.getAudience().iterator().next(); // TODO: 이전 버전과 다르게 aud가 Set으로 변경되어 있음. 테스트 필요 + log.debug("aud : {}", aud); + + return new OidcDecodePayload( + body.getIssuer(), + aud, + body.getSubject(), + body.get("email", String.class)); + } + + /** + * ID Token의 header와 body를 Base64 방식으로 디코딩하는 메서드
+ * payload의 iss, aud, exp, nonce를 검증하고, 실패시 예외 처리 + */ + private Jwt getUnsignedTokenClaims(String token, String iss, String aud, String nonce) { + try { + return Jwts.parser() + .requireAudience(aud) + .requireIssuer(iss) +// .require("nonce", nonce) // 현재는 nonce를 사용하지 않음 + .build() + .parseUnsecuredClaims(getUnsignedToken(token)); // TODO: 기존 방식은 parseClaimsJwt(getUnsignedToken(token)); -> 변경한 코드 정상 동작 여부 확인 필요 + } catch (JwtException e) { + final JwtErrorCode errorCode = JwtErrorCodeUtil.determineErrorCode(e, JwtErrorCode.FAILED_AUTHENTICATION); + + log.warn("Error code : {}, Error - {}, {}", errorCode, e.getClass(), e.getMessage()); + throw new JwtErrorException(errorCode); + } + } + + /** + * Token의 signature를 제거하는 메서드 + */ + private String getUnsignedToken(String token) { + String[] splitToken = token.split("\\."); + if (splitToken.length != 3) throw new JwtErrorException(JwtErrorCode.MALFORMED_TOKEN); + return splitToken[0] + "." + splitToken[1] + "."; + } + + /** + * 공개키로 서명을 검증하는 메서드 + */ + private Jws getOIDCTokenJws(String token, String modulus, String exponent) { + try { + log.info("token : {}", token); + return Jwts.parser() + .verifyWith(getRSAPublicKey(modulus, exponent)) + .build() + .parseSignedClaims(token); + } catch (JwtException e) { + final JwtErrorCode errorCode = JwtErrorCodeUtil.determineErrorCode(e, JwtErrorCode.FAILED_AUTHENTICATION); + + log.warn("Error code : {}, Error - {}, {}", errorCode, e.getClass(), e.getMessage()); + throw new JwtErrorException(errorCode); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + log.warn("Error - {}, {}", e.getClass(), e.getMessage()); + throw new JwtErrorException(JwtErrorCode.MALFORMED_TOKEN); + } + } + + /** + * n, e 조합으로 공개키를 생성하는 메서드 + */ + private PublicKey getRSAPublicKey(String modulus, String exponent) throws NoSuchAlgorithmException, InvalidKeySpecException { + KeyFactory keyFactory = KeyFactory.getInstance(RSA); + byte[] decodeN = Base64.getUrlDecoder().decode(modulus); + byte[] decodeE = Base64.getUrlDecoder().decode(exponent); + BigInteger n = new BigInteger(1, decodeN); + BigInteger e = new BigInteger(1, decodeE); + + RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(n, e); + return keyFactory.generatePublic(publicKeySpec); + } +} \ No newline at end of file diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcDecodePayload.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcDecodePayload.java new file mode 100644 index 000000000..7049056fb --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcDecodePayload.java @@ -0,0 +1,12 @@ +package kr.co.pennyway.infra.common.oidc; + +public record OidcDecodePayload( + /* issuer */ + String iss, + /* client id */ + String aud, + /* aouth provider account unique id */ + String sub, + String email +) { +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKey.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKey.java new file mode 100644 index 000000000..0fe4011f1 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKey.java @@ -0,0 +1,11 @@ +package kr.co.pennyway.infra.common.oidc; + +public record OidcPublicKey( + String kid, + String kty, + String alg, + String use, + String n, + String e +) { +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKeyResponse.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKeyResponse.java new file mode 100644 index 000000000..15a392c67 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/oidc/OidcPublicKeyResponse.java @@ -0,0 +1,19 @@ +package kr.co.pennyway.infra.common.oidc; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Getter +@NoArgsConstructor +public class OidcPublicKeyResponse { + List keys; + + @Override + public String toString() { + return "OIDCPublicKeyResponse{" + + "keys=" + keys + + '}'; + } +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/AppleOidcProperties.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/AppleOidcProperties.java new file mode 100644 index 000000000..d953b2285 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/AppleOidcProperties.java @@ -0,0 +1,14 @@ +package kr.co.pennyway.infra.common.properties; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClientProperties; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Getter +@RequiredArgsConstructor +@ConfigurationProperties(prefix = "oauth2.client.provider.apple") +public class AppleOidcProperties implements OauthOidcClientProperties { + private final String jwksUri; + private final String secret; +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/GoogleOidcProperties.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/GoogleOidcProperties.java new file mode 100644 index 000000000..b61e61078 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/GoogleOidcProperties.java @@ -0,0 +1,14 @@ +package kr.co.pennyway.infra.common.properties; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClientProperties; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Getter +@RequiredArgsConstructor +@ConfigurationProperties(prefix = "oauth2.client.provider.google") +public class GoogleOidcProperties implements OauthOidcClientProperties { + private final String jwksUri; + private final String secret; +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/KakaoOidcProperties.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/KakaoOidcProperties.java new file mode 100644 index 000000000..e7d3f90a2 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/common/properties/KakaoOidcProperties.java @@ -0,0 +1,14 @@ +package kr.co.pennyway.infra.common.properties; + +import kr.co.pennyway.infra.common.oidc.OauthOidcClientProperties; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Getter +@RequiredArgsConstructor +@ConfigurationProperties(prefix = "oauth2.client.provider.kakao") +public class KakaoOidcProperties implements OauthOidcClientProperties { + private final String jwksUri; + private final String secret; +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/CacheConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/CacheConfig.java index 4c51e7a59..a84c56992 100644 --- a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/CacheConfig.java +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/CacheConfig.java @@ -100,7 +100,7 @@ public CacheManager securityUserCacheManager(@InfraRedisConnectionFactory RedisC @Bean @OidcCacheManager - public CacheManager oidcCacheManger(@InfraRedisConnectionFactory RedisConnectionFactory cf) { + public CacheManager oidcCacheManager(@InfraRedisConnectionFactory RedisConnectionFactory cf) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith( RedisSerializationContext.SerializationPair.fromSerializer( diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/ConfigurationPropertiesConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/ConfigurationPropertiesConfig.java deleted file mode 100644 index 63c859194..000000000 --- a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/ConfigurationPropertiesConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package kr.co.pennyway.infra.config; - -import kr.co.pennyway.infra.common.properties.ServerProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@EnableConfigurationProperties({ - ServerProperties.class -}) -@Configuration -public class ConfigurationPropertiesConfig { -} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/DefaultFeignConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/DefaultFeignConfig.java new file mode 100644 index 000000000..07ee11df4 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/DefaultFeignConfig.java @@ -0,0 +1,18 @@ +package kr.co.pennyway.infra.config; + +import feign.codec.Encoder; +import feign.form.FormEncoder; +import feign.okhttp.OkHttpClient; +import org.springframework.context.annotation.Bean; + +public class DefaultFeignConfig { + @Bean + public OkHttpClient client() { + return new OkHttpClient(); + } + + @Bean + Encoder formEncoder() { + return new FormEncoder(); + } +} diff --git a/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/FeignConfig.java b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/FeignConfig.java new file mode 100644 index 000000000..564fd5057 --- /dev/null +++ b/pennyway-infra/src/main/java/kr/co/pennyway/infra/config/FeignConfig.java @@ -0,0 +1,13 @@ +package kr.co.pennyway.infra.config; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.cloud.openfeign.clientconfig.HttpClient5FeignConfiguration; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableFeignClients(basePackages = "kr.co.pennyway.infra") +@ImportAutoConfiguration({FeignAutoConfiguration.class, HttpClient5FeignConfiguration.class}) +public class FeignConfig { +} diff --git a/pennyway-infra/src/main/resources/application-infra.yml b/pennyway-infra/src/main/resources/application-infra.yml index f9c75be13..5b963497d 100644 --- a/pennyway-infra/src/main/resources/application-infra.yml +++ b/pennyway-infra/src/main/resources/application-infra.yml @@ -10,6 +10,19 @@ pennyway: local: ${PENNYWAY_DOMAIN_LOCAL} dev: ${PENNYWAY_DOMAIN_DEV} +oauth2: + client: + provider: + kakao: + jwks-uri: ${KAKAO_JWKS_URI} + secret: ${KAKAO_CLIENT_SECRET} + google: + jwks-uri: ${GOOGLE_JWKS_URI} + secret: ${GOOGLE_CLIENT_SECRET} + apple: + jwks-uri: ${APPLE_JWKS_URI} + secret: ${APPLE_CLIENT_SECRET} + --- spring: config: