diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/AuthController.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/AuthController.java similarity index 74% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/AuthController.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/AuthController.java index c40943f..c12cc17 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/AuthController.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/AuthController.java @@ -1,14 +1,18 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; import org.apache.commons.lang3.StringUtils; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.UserRegisterRequest; -import org.clevercastle.helper.login.UserService; -import org.clevercastle.helper.login.UserWithToken; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; -import org.clevercastle.helper.login.oauth2.github.GithubOauth2ExchangeService; -import org.clevercastle.helper.login.oauth2.oidc.OidcExchangeService; +import org.apache.commons.lang3.tuple.Pair; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.UserRegisterRequest; +import org.clevercastle.authforge.UserService; +import org.clevercastle.authforge.UserWithToken; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.oauth2.github.GithubOauth2ExchangeService; +import org.clevercastle.authforge.oauth2.oidc.OidcExchangeService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -16,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.text.ParseException; import java.util.Base64; import java.util.List; @@ -96,6 +101,24 @@ public UserWithToken login(@RequestHeader String authorization) throws CastleExc return userService.login(loginIdentifier, password); } + @GetMapping("auth/refresh") + public UserWithToken login(@RequestHeader String authorization, @RequestBody RefreshTokenRequest refreshToken) throws CastleException, ParseException { + // decode basic authentication + authorization = authorization.replace("Bearer ", ""); + // TODO: 2025/4/29 verify the token + DecodedJWT jwt = JWT.decode(authorization); + final String userSub = jwt.getSubject(); + if (StringUtils.isBlank(userSub)) { + throw new CastleException(""); + } + userService.getByLoginIdentifier(userSub); + Pair pair = userService.getByUserSub(userSub); + if (pair.getLeft() == null || pair.getRight() == null) { + throw new CastleException(""); + } + return userService.refresh(pair.getLeft(), pair.getRight(), refreshToken.getRefreshToken()); + } + @GetMapping("auth/sso/url") public String generateUrl(@RequestParam SsoType ssoType, @RequestParam String redirectUrl) { // decode basic authentication diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/Beans.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/Beans.java similarity index 71% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/Beans.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/Beans.java index 641a1c0..e74b205 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/Beans.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/Beans.java @@ -1,16 +1,17 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; import com.auth0.jwt.algorithms.Algorithm; -import org.clevercastle.helper.login.Config; -import org.clevercastle.helper.login.UserService; -import org.clevercastle.helper.login.UserServiceImpl; -import org.clevercastle.helper.login.repository.UserRepository; -import org.clevercastle.helper.login.repository.rdsjpa.IUserLoginItemRepository; -import org.clevercastle.helper.login.repository.rdsjpa.IUserModelRepository; -import org.clevercastle.helper.login.repository.rdsjpa.UserRepositoryImpl; -import org.clevercastle.helper.login.token.TokenService; -import org.clevercastle.helper.login.token.jwt.JwtTokenService; -import org.clevercastle.helper.login.verification.DummyVerificationService; +import org.clevercastle.authforge.Config; +import org.clevercastle.authforge.UserService; +import org.clevercastle.authforge.UserServiceImpl; +import org.clevercastle.authforge.repository.UserRepository; +import org.clevercastle.authforge.repository.rdsjpa.IUserLoginItemRepository; +import org.clevercastle.authforge.repository.rdsjpa.IUserModelRepository; +import org.clevercastle.authforge.repository.rdsjpa.IUserRefreshTokenMappingRepository; +import org.clevercastle.authforge.repository.rdsjpa.UserRepositoryImpl; +import org.clevercastle.authforge.token.TokenService; +import org.clevercastle.authforge.token.jwt.JwtTokenService; +import org.clevercastle.authforge.verification.DummyVerificationService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -31,8 +32,9 @@ public class Beans { @Bean public UserRepository userRepository(IUserModelRepository userModelRepository, - IUserLoginItemRepository userLoginItemRepository) { - return new UserRepositoryImpl(userModelRepository, userLoginItemRepository); + IUserLoginItemRepository userLoginItemRepository, + IUserRefreshTokenMappingRepository userRefreshTokenMappingRepository) { + return new UserRepositoryImpl(userModelRepository, userLoginItemRepository, userRefreshTokenMappingRepository); } @Bean @@ -50,7 +52,7 @@ public TokenService tokenService() throws NoSuchAlgorithmException, InvalidKeySp // Validate the key type and curve var algorithm = Algorithm.ECDSA256((ECPublicKey) publicKey, (ECPrivateKey) privateKey); - return new JwtTokenService(algorithm, "kid"); + return new JwtTokenService(Config.builder().build(), "client-01", "kid", algorithm); } @Bean diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/HttpClientImpl.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/HttpClientImpl.java similarity index 86% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/HttpClientImpl.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/HttpClientImpl.java index 35f037a..bc96464 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/HttpClientImpl.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/HttpClientImpl.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; import org.apache.hc.client5.http.config.RequestConfig; @@ -7,10 +7,10 @@ import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.util.Timeout; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.http.HttpRequest; -import org.clevercastle.helper.login.http.HttpResponse; -import org.clevercastle.helper.login.http.IHttpClient; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.http.HttpRequest; +import org.clevercastle.authforge.http.HttpResponse; +import org.clevercastle.authforge.http.IHttpClient; import java.io.IOException; import java.net.URI; diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RefreshTokenRequest.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RefreshTokenRequest.java new file mode 100644 index 0000000..50c3356 --- /dev/null +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RefreshTokenRequest.java @@ -0,0 +1,13 @@ +package org.clevercastle.authforge.examples.springboot.springbootexample; + +public class RefreshTokenRequest { + private String refreshToken; + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } +} diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/RegisterRequest.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RegisterRequest.java similarity index 83% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/RegisterRequest.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RegisterRequest.java index 9611093..3e2a9b7 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/RegisterRequest.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/RegisterRequest.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; public class RegisterRequest { private String email; diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SpringBootExampleApplication.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SpringBootExampleApplication.java similarity index 78% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SpringBootExampleApplication.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SpringBootExampleApplication.java index 61c0eb6..ead3e70 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SpringBootExampleApplication.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SpringBootExampleApplication.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; -import org.clevercastle.helper.login.User; +import org.clevercastle.authforge.User; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SsoType.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SsoType.java new file mode 100644 index 0000000..99c6c37 --- /dev/null +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/SsoType.java @@ -0,0 +1,6 @@ +package org.clevercastle.authforge.examples.springboot.springbootexample; + +public enum SsoType { + github, + google +} diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java similarity index 54% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java index 41c0782..4f9c006 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserLoginItemRepositoryAdapter.java @@ -1,7 +1,7 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; -import org.clevercastle.helper.login.UserLoginItem; -import org.clevercastle.helper.login.repository.rdsjpa.UserLoginItemJpaRepository; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.repository.rdsjpa.UserLoginItemJpaRepository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserModelRepositoryAdapter.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserModelRepositoryAdapter.java similarity index 53% rename from examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserModelRepositoryAdapter.java rename to examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserModelRepositoryAdapter.java index a38c550..8da6c66 100644 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/UserModelRepositoryAdapter.java +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserModelRepositoryAdapter.java @@ -1,7 +1,7 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; +package org.clevercastle.authforge.examples.springboot.springbootexample; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.repository.rdsjpa.IUserModelRepository; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.repository.rdsjpa.IUserModelRepository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserRefreshTokenMappingRepositoryAdapter.java b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserRefreshTokenMappingRepositoryAdapter.java new file mode 100644 index 0000000..0b702f3 --- /dev/null +++ b/examples/spring-boot-example/src/main/java/org/clevercastle/authforge/examples/springboot/springbootexample/UserRefreshTokenMappingRepositoryAdapter.java @@ -0,0 +1,9 @@ +package org.clevercastle.authforge.examples.springboot.springbootexample; + +import org.clevercastle.authforge.UserRefreshTokenMapping; +import org.clevercastle.authforge.repository.rdsjpa.IUserRefreshTokenMappingRepository; +import org.clevercastle.authforge.repository.rdsjpa.UserRefreshTokenMappingId; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRefreshTokenMappingRepositoryAdapter extends IUserRefreshTokenMappingRepository, JpaRepository { +} diff --git a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SsoType.java b/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SsoType.java deleted file mode 100644 index e4acc9d..0000000 --- a/examples/spring-boot-example/src/main/java/org/clevercastle/helper/login/examples/springboot/springbootexample/SsoType.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.clevercastle.helper.login.examples.springboot.springbootexample; - -public enum SsoType { - github, - google -} diff --git a/src/main/java/org/clevercastle/helper/login/CastleException.java b/src/main/java/org/clevercastle/authforge/CastleException.java similarity index 86% rename from src/main/java/org/clevercastle/helper/login/CastleException.java rename to src/main/java/org/clevercastle/authforge/CastleException.java index 84ffa05..802f28d 100644 --- a/src/main/java/org/clevercastle/helper/login/CastleException.java +++ b/src/main/java/org/clevercastle/authforge/CastleException.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; public class CastleException extends Exception { public CastleException() { diff --git a/src/main/java/org/clevercastle/authforge/Config.java b/src/main/java/org/clevercastle/authforge/Config.java new file mode 100644 index 0000000..44e2822 --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/Config.java @@ -0,0 +1,50 @@ +package org.clevercastle.authforge; + +public class Config { + // in seconds + private int verificationCodeExpireTime; + // in seconds + private int tokenExpireTime; + + public int getVerificationCodeExpireTime() { + return verificationCodeExpireTime; + } + + public int getTokenExpireTime() { + return tokenExpireTime; + } + + + public static ConfigBuilder builder() { + return new ConfigBuilder(); + } + + public static final class ConfigBuilder { + private int verificationCodeExpireTime = 300; + private int tokenExpireTime = 28400; + + private ConfigBuilder() { + } + + public static ConfigBuilder aConfig() { + return new ConfigBuilder(); + } + + public ConfigBuilder verificationCodeExpireTime(int verificationCodeExpireTime) { + this.verificationCodeExpireTime = verificationCodeExpireTime; + return this; + } + + public ConfigBuilder tokenExpireTime(int tokenExpireTime) { + this.tokenExpireTime = tokenExpireTime; + return this; + } + + public Config build() { + Config config = new Config(); + config.verificationCodeExpireTime = this.verificationCodeExpireTime; + config.tokenExpireTime = this.tokenExpireTime; + return config; + } + } +} diff --git a/src/main/java/org/clevercastle/helper/login/RefreshToken.java b/src/main/java/org/clevercastle/authforge/RefreshToken.java similarity index 95% rename from src/main/java/org/clevercastle/helper/login/RefreshToken.java rename to src/main/java/org/clevercastle/authforge/RefreshToken.java index 3eb36f4..9a0d505 100644 --- a/src/main/java/org/clevercastle/helper/login/RefreshToken.java +++ b/src/main/java/org/clevercastle/authforge/RefreshToken.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import jakarta.annotation.Nonnull; diff --git a/src/main/java/org/clevercastle/helper/login/TokenHolder.java b/src/main/java/org/clevercastle/authforge/TokenHolder.java similarity index 97% rename from src/main/java/org/clevercastle/helper/login/TokenHolder.java rename to src/main/java/org/clevercastle/authforge/TokenHolder.java index 8ae65c4..cf4ed0c 100644 --- a/src/main/java/org/clevercastle/helper/login/TokenHolder.java +++ b/src/main/java/org/clevercastle/authforge/TokenHolder.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import java.time.OffsetDateTime; diff --git a/src/main/java/org/clevercastle/helper/login/User.java b/src/main/java/org/clevercastle/authforge/User.java similarity index 96% rename from src/main/java/org/clevercastle/helper/login/User.java rename to src/main/java/org/clevercastle/authforge/User.java index 5530ff1..0184935 100644 --- a/src/main/java/org/clevercastle/helper/login/User.java +++ b/src/main/java/org/clevercastle/authforge/User.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -24,8 +24,6 @@ public class User { private String resetPasswordCode; private OffsetDateTime resetPasswordCodeExpiredAt; -// private Set refreshTokens; - private OffsetDateTime createdAt; private OffsetDateTime updatedAt; diff --git a/src/main/java/org/clevercastle/helper/login/UserLoginItem.java b/src/main/java/org/clevercastle/authforge/UserLoginItem.java similarity index 98% rename from src/main/java/org/clevercastle/helper/login/UserLoginItem.java rename to src/main/java/org/clevercastle/authforge/UserLoginItem.java index 31012e7..3bc78e1 100644 --- a/src/main/java/org/clevercastle/helper/login/UserLoginItem.java +++ b/src/main/java/org/clevercastle/authforge/UserLoginItem.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; diff --git a/src/main/java/org/clevercastle/authforge/UserRefreshTokenMapping.java b/src/main/java/org/clevercastle/authforge/UserRefreshTokenMapping.java new file mode 100644 index 0000000..c311756 --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/UserRefreshTokenMapping.java @@ -0,0 +1,60 @@ +package org.clevercastle.authforge; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; +import org.clevercastle.authforge.repository.rdsjpa.UserRefreshTokenMappingId; + +import java.time.OffsetDateTime; + +@javax.persistence.Entity +@javax.persistence.Table(name = "user_refresh_token") +@Entity +@Table(name = "user_refresh_token") +@javax.persistence.IdClass(UserRefreshTokenMappingId.class) +@IdClass(UserRefreshTokenMappingId.class) +public class UserRefreshTokenMapping { + @javax.persistence.Id + @Id + private String userId; + @javax.persistence.Id + @Id + private String refreshToken; + + private OffsetDateTime createdAt; + private OffsetDateTime expiredAt; + + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + public OffsetDateTime getExpiredAt() { + return expiredAt; + } + + public void setExpiredAt(OffsetDateTime expiredAt) { + this.expiredAt = expiredAt; + } +} diff --git a/src/main/java/org/clevercastle/helper/login/UserRegisterRequest.java b/src/main/java/org/clevercastle/authforge/UserRegisterRequest.java similarity index 94% rename from src/main/java/org/clevercastle/helper/login/UserRegisterRequest.java rename to src/main/java/org/clevercastle/authforge/UserRegisterRequest.java index 69d1ff6..eb2520d 100644 --- a/src/main/java/org/clevercastle/helper/login/UserRegisterRequest.java +++ b/src/main/java/org/clevercastle/authforge/UserRegisterRequest.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; public class UserRegisterRequest { private String loginIdentifier; diff --git a/src/main/java/org/clevercastle/helper/login/UserService.java b/src/main/java/org/clevercastle/authforge/UserService.java similarity index 62% rename from src/main/java/org/clevercastle/helper/login/UserService.java rename to src/main/java/org/clevercastle/authforge/UserService.java index 3fd1be9..3dd59ea 100644 --- a/src/main/java/org/clevercastle/helper/login/UserService.java +++ b/src/main/java/org/clevercastle/authforge/UserService.java @@ -1,7 +1,7 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import org.apache.commons.lang3.tuple.Pair; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; public interface UserService { // used for username/password, email/password, mobile/password @@ -11,10 +11,14 @@ public interface UserService { UserWithToken login(String loginIdentifier, String password) throws CastleException; - Pair get(String loginIdentifier) throws CastleException; + Pair getByLoginIdentifier(String loginIdentifier) throws CastleException; + + Pair getByUserSub(String userSub) throws CastleException; String generate(Oauth2ClientConfig oauth2Client, String redirectUri); + UserWithToken refresh(User user, UserLoginItem userLoginItem, String refreshToken) throws CastleException; + // used for sso login UserWithToken exchange(Oauth2ClientConfig clientConfig, String authorizationCode, String state, String redirectUrl) throws CastleException; } diff --git a/src/main/java/org/clevercastle/helper/login/UserServiceImpl.java b/src/main/java/org/clevercastle/authforge/UserServiceImpl.java similarity index 80% rename from src/main/java/org/clevercastle/helper/login/UserServiceImpl.java rename to src/main/java/org/clevercastle/authforge/UserServiceImpl.java index 61299c3..1366659 100644 --- a/src/main/java/org/clevercastle/helper/login/UserServiceImpl.java +++ b/src/main/java/org/clevercastle/authforge/UserServiceImpl.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; import com.nimbusds.oauth2.sdk.AuthorizationCode; import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; @@ -14,20 +14,21 @@ import jakarta.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import org.clevercastle.helper.login.exception.UserExistException; -import org.clevercastle.helper.login.exception.UserNotFoundException; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; -import org.clevercastle.helper.login.oauth2.Oauth2User; -import org.clevercastle.helper.login.repository.UserRepository; -import org.clevercastle.helper.login.token.TokenService; -import org.clevercastle.helper.login.util.CodeUtil; -import org.clevercastle.helper.login.util.HashUtil; -import org.clevercastle.helper.login.util.IdUtil; -import org.clevercastle.helper.login.util.TimeUtils; -import org.clevercastle.helper.login.verification.VerificationService; +import org.clevercastle.authforge.exception.UserExistException; +import org.clevercastle.authforge.exception.UserNotFoundException; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.oauth2.Oauth2User; +import org.clevercastle.authforge.repository.UserRepository; +import org.clevercastle.authforge.token.TokenService; +import org.clevercastle.authforge.util.CodeUtil; +import org.clevercastle.authforge.util.HashUtil; +import org.clevercastle.authforge.util.IdUtil; +import org.clevercastle.authforge.util.TimeUtils; +import org.clevercastle.authforge.verification.VerificationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.transaction.Transactional; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -54,7 +55,7 @@ public UserServiceImpl(Config config, @Override public User register(UserRegisterRequest userRegisterRequest) throws CastleException { - Pair pair = this.get(userRegisterRequest.getLoginIdentifier()); + Pair pair = this.getByLoginIdentifier(userRegisterRequest.getLoginIdentifier()); User user = pair.getLeft(); if (user != null) { if (UserState.DELETED != user.getUserState()) { @@ -93,7 +94,7 @@ public User register(UserRegisterRequest userRegisterRequest) throws CastleExcep @Override public void verify(String loginIdentifier, String verificationCode) throws CastleException { - Pair pair = this.userRepository.get(loginIdentifier); + Pair pair = this.userRepository.getByLoginIdentifier(loginIdentifier); UserLoginItem userLoginItem = pair.getRight(); if (userLoginItem == null) { throw new UserNotFoundException(); @@ -131,7 +132,7 @@ public UserWithToken exchange(Oauth2ClientConfig clientConfig, String authorizat if (StringUtils.isBlank(oauth2User.getLoginIdentifier())) { throw new CastleException(); } - Pair pair = get(oauth2User.getLoginIdentifier()); + Pair pair = getByLoginIdentifier(oauth2User.getLoginIdentifier()); var user = pair.getLeft(); var userLoginItem = pair.getRight(); if (userLoginItem == null) { @@ -153,6 +154,7 @@ public UserWithToken exchange(Oauth2ClientConfig clientConfig, String authorizat userLoginItem.setUpdatedAt(now); this.userRepository.save(user, userLoginItem); TokenHolder tokenHolder = tokenService.generateToken(user, userLoginItem); + userRepository.addRefreshToken(user, tokenHolder.getRefreshToken(), tokenHolder.getExpiresAt()); return new UserWithToken(user, tokenHolder); } else { // login process @@ -160,13 +162,14 @@ public UserWithToken exchange(Oauth2ClientConfig clientConfig, String authorizat throw new CastleException(""); } TokenHolder tokenHolder = tokenService.generateToken(user, userLoginItem); + userRepository.addRefreshToken(user, tokenHolder.getRefreshToken(), tokenHolder.getExpiresAt()); return new UserWithToken(user, tokenHolder); } } @Override public UserWithToken login(String loginIdentifier, String password) throws CastleException { - Pair pair = get(loginIdentifier); + Pair pair = getByLoginIdentifier(loginIdentifier); var user = pair.getLeft(); var userLoginItem = pair.getRight(); if (user == null) { @@ -183,9 +186,27 @@ public UserWithToken login(String loginIdentifier, String password) throws Castl throw new CastleException("Incorrect password"); } TokenHolder tokenHolder = tokenService.generateToken(user, userLoginItem); + userRepository.addRefreshToken(user, tokenHolder.getRefreshToken(), tokenHolder.getExpiresAt()); return new UserWithToken(user, tokenHolder); } + @Override + @Transactional + public UserWithToken refresh(User user, UserLoginItem userLoginItem, String refreshToken) throws CastleException { + if (UserState.ACTIVE != user.getUserState()) { + throw new CastleException(""); + } + boolean verified = userRepository.verifyRefreshToken(user, refreshToken); + if (verified) { + TokenHolder tokenHolder = tokenService.generateToken(user, userLoginItem); + userRepository.addRefreshToken(user, tokenHolder.getRefreshToken(), tokenHolder.getExpiresAt()); + return new UserWithToken(user, tokenHolder); + } else { + throw new CastleException("Fail to refresh"); + } + } + + /** * get id token from oauth2 provider * @param clientConfig @@ -242,9 +263,12 @@ private OIDCTokenResponse oauth2Exchange(Oauth2ClientConfig clientConfig, String @Nonnull @Override - public Pair get(String loginIdentifier) throws CastleException { - return userRepository.get(loginIdentifier); + public Pair getByLoginIdentifier(String loginIdentifier) throws CastleException { + return userRepository.getByLoginIdentifier(loginIdentifier); } - + @Override + public Pair getByUserSub(String userSub) throws CastleException { + return userRepository.getByUserSub(userSub); + } } diff --git a/src/main/java/org/clevercastle/helper/login/UserState.java b/src/main/java/org/clevercastle/authforge/UserState.java similarity index 62% rename from src/main/java/org/clevercastle/helper/login/UserState.java rename to src/main/java/org/clevercastle/authforge/UserState.java index 91a39df..e62c0ce 100644 --- a/src/main/java/org/clevercastle/helper/login/UserState.java +++ b/src/main/java/org/clevercastle/authforge/UserState.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; public enum UserState { ACTIVE, diff --git a/src/main/java/org/clevercastle/helper/login/UserWithToken.java b/src/main/java/org/clevercastle/authforge/UserWithToken.java similarity index 90% rename from src/main/java/org/clevercastle/helper/login/UserWithToken.java rename to src/main/java/org/clevercastle/authforge/UserWithToken.java index 249665d..a794f98 100644 --- a/src/main/java/org/clevercastle/helper/login/UserWithToken.java +++ b/src/main/java/org/clevercastle/authforge/UserWithToken.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login; +package org.clevercastle.authforge; public class UserWithToken { private final User user; diff --git a/src/main/java/org/clevercastle/authforge/exception/UserExistException.java b/src/main/java/org/clevercastle/authforge/exception/UserExistException.java new file mode 100644 index 0000000..4b0d982 --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/exception/UserExistException.java @@ -0,0 +1,6 @@ +package org.clevercastle.authforge.exception; + +import org.clevercastle.authforge.CastleException; + +public class UserExistException extends CastleException { +} diff --git a/src/main/java/org/clevercastle/helper/login/exception/UserNotConfirmedException.java b/src/main/java/org/clevercastle/authforge/exception/UserNotConfirmedException.java similarity index 52% rename from src/main/java/org/clevercastle/helper/login/exception/UserNotConfirmedException.java rename to src/main/java/org/clevercastle/authforge/exception/UserNotConfirmedException.java index 3e50d01..8eee807 100644 --- a/src/main/java/org/clevercastle/helper/login/exception/UserNotConfirmedException.java +++ b/src/main/java/org/clevercastle/authforge/exception/UserNotConfirmedException.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.exception; +package org.clevercastle.authforge.exception; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; public class UserNotConfirmedException extends CastleException { public UserNotConfirmedException() { diff --git a/src/main/java/org/clevercastle/helper/login/exception/UserNotFoundException.java b/src/main/java/org/clevercastle/authforge/exception/UserNotFoundException.java similarity index 51% rename from src/main/java/org/clevercastle/helper/login/exception/UserNotFoundException.java rename to src/main/java/org/clevercastle/authforge/exception/UserNotFoundException.java index 1a9db2e..a3e826a 100644 --- a/src/main/java/org/clevercastle/helper/login/exception/UserNotFoundException.java +++ b/src/main/java/org/clevercastle/authforge/exception/UserNotFoundException.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.exception; +package org.clevercastle.authforge.exception; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; public class UserNotFoundException extends CastleException { public UserNotFoundException() { diff --git a/src/main/java/org/clevercastle/helper/login/http/HttpRequest.java b/src/main/java/org/clevercastle/authforge/http/HttpRequest.java similarity index 94% rename from src/main/java/org/clevercastle/helper/login/http/HttpRequest.java rename to src/main/java/org/clevercastle/authforge/http/HttpRequest.java index b22286e..0abb0be 100644 --- a/src/main/java/org/clevercastle/helper/login/http/HttpRequest.java +++ b/src/main/java/org/clevercastle/authforge/http/HttpRequest.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.http; +package org.clevercastle.authforge.http; import java.util.Map; diff --git a/src/main/java/org/clevercastle/helper/login/http/HttpResponse.java b/src/main/java/org/clevercastle/authforge/http/HttpResponse.java similarity index 94% rename from src/main/java/org/clevercastle/helper/login/http/HttpResponse.java rename to src/main/java/org/clevercastle/authforge/http/HttpResponse.java index 2826d2b..ec2469b 100644 --- a/src/main/java/org/clevercastle/helper/login/http/HttpResponse.java +++ b/src/main/java/org/clevercastle/authforge/http/HttpResponse.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.http; +package org.clevercastle.authforge.http; import java.util.Map; diff --git a/src/main/java/org/clevercastle/helper/login/http/IHttpClient.java b/src/main/java/org/clevercastle/authforge/http/IHttpClient.java similarity index 51% rename from src/main/java/org/clevercastle/helper/login/http/IHttpClient.java rename to src/main/java/org/clevercastle/authforge/http/IHttpClient.java index 63d18b9..b476072 100644 --- a/src/main/java/org/clevercastle/helper/login/http/IHttpClient.java +++ b/src/main/java/org/clevercastle/authforge/http/IHttpClient.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.http; +package org.clevercastle.authforge.http; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; public interface IHttpClient { HttpResponse execute(HttpRequest request) throws CastleException; diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/AbstractOauth2ExchangeService.java b/src/main/java/org/clevercastle/authforge/oauth2/AbstractOauth2ExchangeService.java similarity index 96% rename from src/main/java/org/clevercastle/helper/login/oauth2/AbstractOauth2ExchangeService.java rename to src/main/java/org/clevercastle/authforge/oauth2/AbstractOauth2ExchangeService.java index 8f969ba..b2163bc 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/AbstractOauth2ExchangeService.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/AbstractOauth2ExchangeService.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2; +package org.clevercastle.authforge.oauth2; import com.nimbusds.oauth2.sdk.AuthorizationCode; import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; @@ -12,7 +12,7 @@ import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.id.ClientID; import org.apache.commons.lang3.StringUtils; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/Avatar.java b/src/main/java/org/clevercastle/authforge/oauth2/Avatar.java similarity index 89% rename from src/main/java/org/clevercastle/helper/login/oauth2/Avatar.java rename to src/main/java/org/clevercastle/authforge/oauth2/Avatar.java index 1767927..09e708d 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/Avatar.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/Avatar.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2; +package org.clevercastle.authforge.oauth2; public class Avatar { public enum Type { diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ClientConfig.java b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2ClientConfig.java similarity index 97% rename from src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ClientConfig.java rename to src/main/java/org/clevercastle/authforge/oauth2/Oauth2ClientConfig.java index 52c40b2..2b29633 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ClientConfig.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2ClientConfig.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.oauth2; +package org.clevercastle.authforge.oauth2; -import org.clevercastle.helper.login.http.IHttpClient; +import org.clevercastle.authforge.http.IHttpClient; import java.util.List; import java.util.Map; diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ExchangeService.java b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2ExchangeService.java similarity index 65% rename from src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ExchangeService.java rename to src/main/java/org/clevercastle/authforge/oauth2/Oauth2ExchangeService.java index 38594d5..89d6b5e 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2ExchangeService.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2ExchangeService.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.oauth2; +package org.clevercastle.authforge.oauth2; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; public interface Oauth2ExchangeService { diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2User.java b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2User.java similarity index 95% rename from src/main/java/org/clevercastle/helper/login/oauth2/Oauth2User.java rename to src/main/java/org/clevercastle/authforge/oauth2/Oauth2User.java index f82ff4d..18c9ec3 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/Oauth2User.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/Oauth2User.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2; +package org.clevercastle.authforge.oauth2; public class Oauth2User { private String loginIdentifier; diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeService.java b/src/main/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeService.java similarity index 87% rename from src/main/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeService.java rename to src/main/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeService.java index b9917d9..124584b 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeService.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeService.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2.github; +package org.clevercastle.authforge.oauth2.github; import com.nimbusds.oauth2.sdk.AccessTokenResponse; import com.nimbusds.oauth2.sdk.TokenErrorResponse; @@ -6,12 +6,12 @@ import com.nimbusds.oauth2.sdk.http.HTTPRequest; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.http.HttpResponse; -import org.clevercastle.helper.login.oauth2.AbstractOauth2ExchangeService; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; -import org.clevercastle.helper.login.oauth2.Oauth2User; -import org.clevercastle.helper.login.util.JsonUtil; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.http.HttpResponse; +import org.clevercastle.authforge.oauth2.AbstractOauth2ExchangeService; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.oauth2.Oauth2User; +import org.clevercastle.authforge.util.JsonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +38,7 @@ protected Oauth2User parse(Oauth2ClientConfig clientConfig, TokenResponse tokenR if (tokenResponse instanceof AccessTokenResponse) { Oauth2User oauth2User = new Oauth2User(); // https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28 - org.clevercastle.helper.login.http.HttpRequest httpRequest = new org.clevercastle.helper.login.http.HttpRequest(); + org.clevercastle.authforge.http.HttpRequest httpRequest = new org.clevercastle.authforge.http.HttpRequest(); httpRequest.setUrl(USER_INFO_API); httpRequest.setMethod("GET"); httpRequest.setBody(null); diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/github/GithubUser.java b/src/main/java/org/clevercastle/authforge/oauth2/github/GithubUser.java similarity index 96% rename from src/main/java/org/clevercastle/helper/login/oauth2/github/GithubUser.java rename to src/main/java/org/clevercastle/authforge/oauth2/github/GithubUser.java index d66ba58..bdb84b3 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/github/GithubUser.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/github/GithubUser.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2.github; +package org.clevercastle.authforge.oauth2.github; import java.time.OffsetDateTime; diff --git a/src/main/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeService.java b/src/main/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeService.java similarity index 90% rename from src/main/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeService.java rename to src/main/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeService.java index bb4b1f4..089301b 100644 --- a/src/main/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeService.java +++ b/src/main/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeService.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.oauth2.oidc; +package org.clevercastle.authforge.oauth2.oidc; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.oauth2.sdk.AccessTokenResponse; @@ -6,10 +6,10 @@ import com.nimbusds.oauth2.sdk.TokenResponse; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.oauth2.AbstractOauth2ExchangeService; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; -import org.clevercastle.helper.login.oauth2.Oauth2User; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.oauth2.AbstractOauth2ExchangeService; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.oauth2.Oauth2User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/clevercastle/authforge/repository/UserRepository.java b/src/main/java/org/clevercastle/authforge/repository/UserRepository.java new file mode 100644 index 0000000..c7d2bf6 --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/repository/UserRepository.java @@ -0,0 +1,27 @@ +package org.clevercastle.authforge.repository; + +import org.apache.commons.lang3.tuple.Pair; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.UserRefreshTokenMapping; + +import java.time.OffsetDateTime; + +public interface UserRepository { + void save(User user, UserLoginItem userLoginItem); + + void save(User user); + + void saveLoginItem(UserLoginItem loginItem); + + Pair getByLoginIdentifier(String loginIdentifier); + + Pair getByUserSub(String userSUb); + + void confirmLoginItem(String loginIdentifier); + + UserRefreshTokenMapping addRefreshToken(User user, String refreshToken, OffsetDateTime expiredAt); + + boolean verifyRefreshToken(User user, String refreshToken) throws CastleException; +} \ No newline at end of file diff --git a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserLoginItemRepository.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserLoginItemRepository.java similarity index 58% rename from src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserLoginItemRepository.java rename to src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserLoginItemRepository.java index d288ea4..fe55514 100644 --- a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserLoginItemRepository.java +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserLoginItemRepository.java @@ -1,11 +1,13 @@ -package org.clevercastle.helper.login.repository.rdsjpa; +package org.clevercastle.authforge.repository.rdsjpa; -import org.clevercastle.helper.login.UserLoginItem; +import org.clevercastle.authforge.UserLoginItem; public interface IUserLoginItemRepository { UserLoginItem save(UserLoginItem userLoginItem); UserLoginItem getByLoginIdentifier(String loginIdentifier); + UserLoginItem getByUserSub(String userSub); + void confirmLoginItem(String loginIdentifier); } diff --git a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserModelRepository.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserModelRepository.java similarity index 51% rename from src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserModelRepository.java rename to src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserModelRepository.java index fe2e3d8..4dc2502 100644 --- a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/IUserModelRepository.java +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserModelRepository.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.repository.rdsjpa; +package org.clevercastle.authforge.repository.rdsjpa; -import org.clevercastle.helper.login.User; +import org.clevercastle.authforge.User; public interface IUserModelRepository { User save(User user); diff --git a/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserRefreshTokenMappingRepository.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserRefreshTokenMappingRepository.java new file mode 100644 index 0000000..028c64e --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/IUserRefreshTokenMappingRepository.java @@ -0,0 +1,11 @@ +package org.clevercastle.authforge.repository.rdsjpa; + +import org.clevercastle.authforge.UserRefreshTokenMapping; + +public interface IUserRefreshTokenMappingRepository { + UserRefreshTokenMapping getByUserIdAndRefreshToken(String userIed, String refreshToken); + + void deleteByUserIdAndRefreshToken(String userIed, String refreshToken); + + UserRefreshTokenMapping save(UserRefreshTokenMapping userRefreshTokenMapping); +} diff --git a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserLoginItemJpaRepository.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserLoginItemJpaRepository.java similarity index 91% rename from src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserLoginItemJpaRepository.java rename to src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserLoginItemJpaRepository.java index 8dde8f0..2c974b7 100644 --- a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserLoginItemJpaRepository.java +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserLoginItemJpaRepository.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.repository.rdsjpa; +package org.clevercastle.authforge.repository.rdsjpa; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -7,6 +7,7 @@ import javax.transaction.Transactional; public interface UserLoginItemJpaRepository extends IUserLoginItemRepository { + @Modifying @Transactional @Query("UPDATE UserLoginItem u\n" + diff --git a/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRefreshTokenMappingId.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRefreshTokenMappingId.java new file mode 100644 index 0000000..7f10f5d --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRefreshTokenMappingId.java @@ -0,0 +1,32 @@ +package org.clevercastle.authforge.repository.rdsjpa; + +import java.io.Serializable; + +public class UserRefreshTokenMappingId implements Serializable { + private String userId; + private String refreshToken; + + public UserRefreshTokenMappingId() { + } + + public UserRefreshTokenMappingId(String userId, String refreshToken) { + this.userId = userId; + this.refreshToken = refreshToken; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } +} diff --git a/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRepositoryImpl.java b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRepositoryImpl.java new file mode 100644 index 0000000..063433f --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/repository/rdsjpa/UserRepositoryImpl.java @@ -0,0 +1,94 @@ +package org.clevercastle.authforge.repository.rdsjpa; + +import jakarta.annotation.Nonnull; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.UserRefreshTokenMapping; +import org.clevercastle.authforge.repository.UserRepository; +import org.clevercastle.authforge.util.TimeUtils; + +import java.time.OffsetDateTime; + +public class UserRepositoryImpl implements UserRepository { + private final IUserModelRepository userModelRepository; + private final IUserLoginItemRepository userLoginItemRepository; + private final IUserRefreshTokenMappingRepository userRefreshTokenMappingRepository; + + public UserRepositoryImpl(IUserModelRepository userModelRepository, + IUserLoginItemRepository userLoginItemRepository, + IUserRefreshTokenMappingRepository userRefreshTokenMappingRepository) { + this.userModelRepository = userModelRepository; + this.userLoginItemRepository = userLoginItemRepository; + this.userRefreshTokenMappingRepository = userRefreshTokenMappingRepository; + } + + @Override + public void save(User user, UserLoginItem userLoginItem) { + userModelRepository.save(user); + userLoginItemRepository.save(userLoginItem); + } + + @Override + public void save(User user) { + userModelRepository.save(user); + } + + @Override + public void saveLoginItem(UserLoginItem loginItem) { + userLoginItemRepository.save(loginItem); + } + + @Override + public Pair getByLoginIdentifier(String loginIdentifier) { + UserLoginItem userLoginItem = userLoginItemRepository.getByLoginIdentifier(loginIdentifier); + if (userLoginItem != null) { + return Pair.of(userModelRepository.getByUserId(userLoginItem.getUserId()), userLoginItem); + } + return Pair.of(null, null); + } + + @Override + public void confirmLoginItem(String loginIdentifier) { + userLoginItemRepository.confirmLoginItem(loginIdentifier); + } + + @Override + public UserRefreshTokenMapping addRefreshToken(User user, String refreshToken, OffsetDateTime expiredAt) { + UserRefreshTokenMapping mapping = new UserRefreshTokenMapping(); + mapping.setUserId(user.getUserId()); + mapping.setRefreshToken(refreshToken); + OffsetDateTime now = OffsetDateTime.now(); + mapping.setCreatedAt(now); + mapping.setExpiredAt(expiredAt); + userRefreshTokenMappingRepository.save(mapping); + return mapping; + } + + @Override + public boolean verifyRefreshToken(@Nonnull User user, String refreshToken) throws CastleException { + if (StringUtils.isBlank(refreshToken)) { + return false; + } + UserRefreshTokenMapping mapping = userRefreshTokenMappingRepository.getByUserIdAndRefreshToken(user.getUserId(), refreshToken); + if (mapping == null) { + return false; + } + if (mapping.getExpiredAt() != null && mapping.getExpiredAt().isAfter(TimeUtils.now())) { + userRefreshTokenMappingRepository.deleteByUserIdAndRefreshToken(user.getUserId(), refreshToken); + return true; + } + return false; + } + + @Override + public Pair getByUserSub(String userSub) { + UserLoginItem userLoginItem = userLoginItemRepository.getByUserSub(userSub); + if (userLoginItem != null) { + return Pair.of(userModelRepository.getByUserId(userLoginItem.getUserId()), userLoginItem); + } + return Pair.of(null, null); + } +} diff --git a/src/main/java/org/clevercastle/authforge/token/TokenService.java b/src/main/java/org/clevercastle/authforge/token/TokenService.java new file mode 100644 index 0000000..f79cf48 --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/token/TokenService.java @@ -0,0 +1,15 @@ +package org.clevercastle.authforge.token; + +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.TokenHolder; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.UserLoginItem; + +public interface TokenService { + enum Scope { + access, + id + } + + TokenHolder generateToken(User user, UserLoginItem item) throws CastleException; +} diff --git a/src/main/java/org/clevercastle/authforge/token/jwt/JwtTokenService.java b/src/main/java/org/clevercastle/authforge/token/jwt/JwtTokenService.java new file mode 100644 index 0000000..769430d --- /dev/null +++ b/src/main/java/org/clevercastle/authforge/token/jwt/JwtTokenService.java @@ -0,0 +1,100 @@ +package org.clevercastle.authforge.token.jwt; + +import com.auth0.jwt.algorithms.Algorithm; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.Config; +import org.clevercastle.authforge.TokenHolder; +import org.clevercastle.authforge.User; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.token.TokenService; +import org.clevercastle.authforge.util.JsonUtil; +import org.clevercastle.authforge.util.TimeUtils; + +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class JwtTokenService implements TokenService { + private static final Base64.Encoder base64UrlEncoder = Base64.getUrlEncoder().withoutPadding(); + private static final int REFRESH_TOKEN_LENGTH = 200; + + private final Config config; + private final String clientId; + private final String keyId; + private final Algorithm algorithm; + + public JwtTokenService(Config config, String clientId, String keyId, Algorithm algorithm) { + this.config = config; + this.clientId = clientId; + this.keyId = keyId; + this.algorithm = algorithm; + } + + @Override + public TokenHolder generateToken(User user, UserLoginItem item) throws CastleException { + OffsetDateTime now = TimeUtils.now(); + OffsetDateTime expiredAt = now.plusSeconds(config.getTokenExpireTime()); + TokenHolder tokenHolder = new TokenHolder(); + tokenHolder.setAccessToken(generateOneToken(user, item, now.toEpochSecond(), expiredAt.toEpochSecond(), Scope.access)); + tokenHolder.setIdToken(generateOneToken(user, item, now.toEpochSecond(), expiredAt.toEpochSecond(), Scope.id)); + tokenHolder.setRefreshToken(generateRefreshToken()); + tokenHolder.setExpiresIn(3600 * 8); + tokenHolder.setExpiresAt(expiredAt); + return tokenHolder; + } + + public Map genAccessTokenPayloadMap(User user, UserLoginItem item, long iat, long exp) { + Map payloadMap = new HashMap<>(); + payloadMap.put("sub", item.getUserSub()); + payloadMap.put("iat", iat); + payloadMap.put("exp", exp); + payloadMap.put("client_id", clientId); + payloadMap.put("jti", UUID.randomUUID().toString()); + return payloadMap; + } + + public Map genIdTokenPayloadMap(User user, UserLoginItem item, long iat, long exp) { + Map payloadMap = new HashMap<>(); + payloadMap.put("sub", item.getUserSub()); + payloadMap.put("iat", iat); + payloadMap.put("exp", exp); + payloadMap.put("aud", clientId); + return payloadMap; + } + + public String generateOneToken(User user, UserLoginItem item, long iat, long exp, TokenService.Scope scope) throws CastleException { + Map headerMap = new HashMap<>(); + headerMap.put("alg", algorithm.getName()); + headerMap.put("kid", keyId); + + Map payloadMap = new HashMap<>(); + switch (scope) { + case access: + payloadMap = genAccessTokenPayloadMap(user, item, iat, exp); + break; + case id: + payloadMap = genIdTokenPayloadMap(user, item, iat, exp); + break; + } + + String headerJson = JsonUtil.toJson(headerMap); + String payloadJson = JsonUtil.toJson(payloadMap); + + String header = base64UrlEncoder.encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); + String payload = base64UrlEncoder.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = this.algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); + String signature = base64UrlEncoder.encodeToString(signatureBytes); + return String.format("%s.%s.%s", header, payload, signature); + } + + public String generateRefreshToken() { + StringBuilder result = new StringBuilder(); + while (result.length() < REFRESH_TOKEN_LENGTH) { + result.append(UUID.randomUUID().toString().replace("-", "")); + } + return result.substring(0, REFRESH_TOKEN_LENGTH); + } +} diff --git a/src/main/java/org/clevercastle/helper/login/util/CodeUtil.java b/src/main/java/org/clevercastle/authforge/util/CodeUtil.java similarity index 95% rename from src/main/java/org/clevercastle/helper/login/util/CodeUtil.java rename to src/main/java/org/clevercastle/authforge/util/CodeUtil.java index d7219e8..3720c1d 100644 --- a/src/main/java/org/clevercastle/helper/login/util/CodeUtil.java +++ b/src/main/java/org/clevercastle/authforge/util/CodeUtil.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; import java.util.Random; diff --git a/src/main/java/org/clevercastle/helper/login/util/CryptoUtil.java b/src/main/java/org/clevercastle/authforge/util/CryptoUtil.java similarity index 98% rename from src/main/java/org/clevercastle/helper/login/util/CryptoUtil.java rename to src/main/java/org/clevercastle/authforge/util/CryptoUtil.java index c7794d8..47fd79e 100644 --- a/src/main/java/org/clevercastle/helper/login/util/CryptoUtil.java +++ b/src/main/java/org/clevercastle/authforge/util/CryptoUtil.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/clevercastle/helper/login/util/HashUtil.java b/src/main/java/org/clevercastle/authforge/util/HashUtil.java similarity index 86% rename from src/main/java/org/clevercastle/helper/login/util/HashUtil.java rename to src/main/java/org/clevercastle/authforge/util/HashUtil.java index f828546..ba28375 100644 --- a/src/main/java/org/clevercastle/helper/login/util/HashUtil.java +++ b/src/main/java/org/clevercastle/authforge/util/HashUtil.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; public class HashUtil { public static String hashPassword(String password) { diff --git a/src/main/java/org/clevercastle/helper/login/util/Hex.java b/src/main/java/org/clevercastle/authforge/util/Hex.java similarity index 96% rename from src/main/java/org/clevercastle/helper/login/util/Hex.java rename to src/main/java/org/clevercastle/authforge/util/Hex.java index 4fec208..9593b7d 100644 --- a/src/main/java/org/clevercastle/helper/login/util/Hex.java +++ b/src/main/java/org/clevercastle/authforge/util/Hex.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; public final class Hex { diff --git a/src/main/java/org/clevercastle/helper/login/util/IdUtil.java b/src/main/java/org/clevercastle/authforge/util/IdUtil.java similarity index 75% rename from src/main/java/org/clevercastle/helper/login/util/IdUtil.java rename to src/main/java/org/clevercastle/authforge/util/IdUtil.java index 3643430..de12e12 100644 --- a/src/main/java/org/clevercastle/helper/login/util/IdUtil.java +++ b/src/main/java/org/clevercastle/authforge/util/IdUtil.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; import java.util.UUID; diff --git a/src/main/java/org/clevercastle/helper/login/util/JsonUtil.java b/src/main/java/org/clevercastle/authforge/util/JsonUtil.java similarity index 98% rename from src/main/java/org/clevercastle/helper/login/util/JsonUtil.java rename to src/main/java/org/clevercastle/authforge/util/JsonUtil.java index c510c13..15145f2 100644 --- a/src/main/java/org/clevercastle/helper/login/util/JsonUtil.java +++ b/src/main/java/org/clevercastle/authforge/util/JsonUtil.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/src/main/java/org/clevercastle/helper/login/util/TimeUtils.java b/src/main/java/org/clevercastle/authforge/util/TimeUtils.java similarity index 99% rename from src/main/java/org/clevercastle/helper/login/util/TimeUtils.java rename to src/main/java/org/clevercastle/authforge/util/TimeUtils.java index fcd3153..daa1bdc 100644 --- a/src/main/java/org/clevercastle/helper/login/util/TimeUtils.java +++ b/src/main/java/org/clevercastle/authforge/util/TimeUtils.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; diff --git a/src/main/java/org/clevercastle/helper/login/verification/AbstractVerificationService.java b/src/main/java/org/clevercastle/authforge/verification/AbstractVerificationService.java similarity index 81% rename from src/main/java/org/clevercastle/helper/login/verification/AbstractVerificationService.java rename to src/main/java/org/clevercastle/authforge/verification/AbstractVerificationService.java index 36b5c32..60ba7b2 100644 --- a/src/main/java/org/clevercastle/helper/login/verification/AbstractVerificationService.java +++ b/src/main/java/org/clevercastle/authforge/verification/AbstractVerificationService.java @@ -1,10 +1,10 @@ -package org.clevercastle.helper.login.verification; +package org.clevercastle.authforge.verification; import org.apache.commons.lang3.StringUtils; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.UserLoginItem; -import org.clevercastle.helper.login.repository.rdsjpa.IUserLoginItemRepository; -import org.clevercastle.helper.login.util.TimeUtils; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.UserLoginItem; +import org.clevercastle.authforge.repository.rdsjpa.IUserLoginItemRepository; +import org.clevercastle.authforge.util.TimeUtils; public abstract class AbstractVerificationService implements VerificationService { private final IUserLoginItemRepository userLoginItemRepository; diff --git a/src/main/java/org/clevercastle/helper/login/verification/DummyVerificationService.java b/src/main/java/org/clevercastle/authforge/verification/DummyVerificationService.java similarity index 75% rename from src/main/java/org/clevercastle/helper/login/verification/DummyVerificationService.java rename to src/main/java/org/clevercastle/authforge/verification/DummyVerificationService.java index 5cb7e78..73bc994 100644 --- a/src/main/java/org/clevercastle/helper/login/verification/DummyVerificationService.java +++ b/src/main/java/org/clevercastle/authforge/verification/DummyVerificationService.java @@ -1,7 +1,7 @@ -package org.clevercastle.helper.login.verification; +package org.clevercastle.authforge.verification; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.repository.rdsjpa.IUserLoginItemRepository; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.repository.rdsjpa.IUserLoginItemRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/clevercastle/helper/login/verification/SendVerificationCodeResponse.java b/src/main/java/org/clevercastle/authforge/verification/SendVerificationCodeResponse.java similarity index 84% rename from src/main/java/org/clevercastle/helper/login/verification/SendVerificationCodeResponse.java rename to src/main/java/org/clevercastle/authforge/verification/SendVerificationCodeResponse.java index 95c45fd..e070c68 100644 --- a/src/main/java/org/clevercastle/helper/login/verification/SendVerificationCodeResponse.java +++ b/src/main/java/org/clevercastle/authforge/verification/SendVerificationCodeResponse.java @@ -1,4 +1,4 @@ -package org.clevercastle.helper.login.verification; +package org.clevercastle.authforge.verification; public class SendVerificationCodeResponse { public enum Type { diff --git a/src/main/java/org/clevercastle/helper/login/verification/VerificationService.java b/src/main/java/org/clevercastle/authforge/verification/VerificationService.java similarity index 69% rename from src/main/java/org/clevercastle/helper/login/verification/VerificationService.java rename to src/main/java/org/clevercastle/authforge/verification/VerificationService.java index 0dce487..e68f8f0 100644 --- a/src/main/java/org/clevercastle/helper/login/verification/VerificationService.java +++ b/src/main/java/org/clevercastle/authforge/verification/VerificationService.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.verification; +package org.clevercastle.authforge.verification; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; public interface VerificationService { void sendVerificationCode(String loginIdentifier, String verificationCode) throws CastleException; diff --git a/src/main/java/org/clevercastle/helper/login/Config.java b/src/main/java/org/clevercastle/helper/login/Config.java deleted file mode 100644 index ba586d7..0000000 --- a/src/main/java/org/clevercastle/helper/login/Config.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.clevercastle.helper.login; - -public class Config { - // in seconds - private int verificationCodeExpireTime; - - public int getVerificationCodeExpireTime() { - return verificationCodeExpireTime; - } - - public static Builder builder() { - return new Builder(); - } - - public static final class Builder { - private int verificationCodeExpireTime = 20; - - private Builder() { - } - - public Builder verificationCodeExpireTime(int verificationCodeExpireTime) { - this.verificationCodeExpireTime = verificationCodeExpireTime; - return this; - } - - public Config build() { - Config config = new Config(); - config.verificationCodeExpireTime = this.verificationCodeExpireTime; - return config; - } - } -} diff --git a/src/main/java/org/clevercastle/helper/login/exception/UserExistException.java b/src/main/java/org/clevercastle/helper/login/exception/UserExistException.java deleted file mode 100644 index db077f8..0000000 --- a/src/main/java/org/clevercastle/helper/login/exception/UserExistException.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.clevercastle.helper.login.exception; - -import org.clevercastle.helper.login.CastleException; - -public class UserExistException extends CastleException { -} diff --git a/src/main/java/org/clevercastle/helper/login/repository/UserRepository.java b/src/main/java/org/clevercastle/helper/login/repository/UserRepository.java deleted file mode 100644 index 12ad4fd..0000000 --- a/src/main/java/org/clevercastle/helper/login/repository/UserRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.clevercastle.helper.login.repository; - -import org.apache.commons.lang3.tuple.Pair; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.UserLoginItem; - -public interface UserRepository { - void save(User user, UserLoginItem userLoginItem); - - void save(User user); - - void saveLoginItem(UserLoginItem loginItem); - - Pair get(String loginIdentifier); - - void confirmLoginItem(String loginIdentifier); -} \ No newline at end of file diff --git a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserRepositoryImpl.java b/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserRepositoryImpl.java deleted file mode 100644 index 237ae31..0000000 --- a/src/main/java/org/clevercastle/helper/login/repository/rdsjpa/UserRepositoryImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.clevercastle.helper.login.repository.rdsjpa; - -import org.apache.commons.lang3.tuple.Pair; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.UserLoginItem; -import org.clevercastle.helper.login.repository.UserRepository; - -public class UserRepositoryImpl implements UserRepository { - private final IUserModelRepository userModelRepository; - private final IUserLoginItemRepository userLoginItemRepository; - - public UserRepositoryImpl(IUserModelRepository userModelRepository, IUserLoginItemRepository userLoginItemRepository) { - this.userModelRepository = userModelRepository; - this.userLoginItemRepository = userLoginItemRepository; - } - - @Override - public void save(User user, UserLoginItem userLoginItem) { - userModelRepository.save(user); - userLoginItemRepository.save(userLoginItem); - } - - @Override - public void save(User user) { - userModelRepository.save(user); - } - - @Override - public void saveLoginItem(UserLoginItem loginItem) { - userLoginItemRepository.save(loginItem); - } - - @Override - public Pair get(String loginIdentifier) { - UserLoginItem userLoginItem = userLoginItemRepository.getByLoginIdentifier(loginIdentifier); - if (userLoginItem != null) { - return Pair.of(userModelRepository.getByUserId(userLoginItem.getUserId()), userLoginItem); - } - return Pair.of(null, null); - } - - @Override - public void confirmLoginItem(String loginIdentifier) { - userLoginItemRepository.confirmLoginItem(loginIdentifier); - } -} diff --git a/src/main/java/org/clevercastle/helper/login/token/TokenService.java b/src/main/java/org/clevercastle/helper/login/token/TokenService.java deleted file mode 100644 index a137373..0000000 --- a/src/main/java/org/clevercastle/helper/login/token/TokenService.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.clevercastle.helper.login.token; - -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.TokenHolder; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.UserLoginItem; - -import java.time.OffsetDateTime; - -public interface TokenService { - TokenHolder generateToken(User user, UserLoginItem item) throws CastleException; -} diff --git a/src/main/java/org/clevercastle/helper/login/token/jwt/JwtTokenService.java b/src/main/java/org/clevercastle/helper/login/token/jwt/JwtTokenService.java deleted file mode 100644 index 1154335..0000000 --- a/src/main/java/org/clevercastle/helper/login/token/jwt/JwtTokenService.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.clevercastle.helper.login.token.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import org.apache.commons.lang3.StringUtils; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.TokenHolder; -import org.clevercastle.helper.login.User; -import org.clevercastle.helper.login.UserLoginItem; -import org.clevercastle.helper.login.token.TokenService; -import org.clevercastle.helper.login.util.JsonUtil; -import org.clevercastle.helper.login.util.TimeUtils; - -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -public class JwtTokenService implements TokenService { - private static final Base64.Encoder base64UrlEncoder = Base64.getUrlEncoder().withoutPadding(); - - private final String keyId; - private final Algorithm algorithm; - - public JwtTokenService(Algorithm algorithm, String keyId) { - this.keyId = keyId; - this.algorithm = algorithm; - } - - @Override - public TokenHolder generateToken(User user, UserLoginItem item) throws CastleException { - OffsetDateTime now = TimeUtils.now(); - // todo customize the expire time - OffsetDateTime expiredAt = now.plusHours(8); - TokenHolder tokenHolder = new TokenHolder(); - tokenHolder.setAccessToken(generateOneToken(user, item, now.toEpochSecond(), expiredAt.toEpochSecond())); - tokenHolder.setIdToken(generateOneToken(user, item, now.toEpochSecond(), expiredAt.toEpochSecond())); - // TODO: 2025/3/29 refresh token - tokenHolder.setExpiresIn(3600 * 8); - tokenHolder.setExpiresAt(expiredAt); - return tokenHolder; - } - - public String generateOneToken(User user, UserLoginItem item, long iat, long exp) throws CastleException { - Map headerMap = new HashMap<>(); - headerMap.put("alg", algorithm.getName()); - headerMap.put("kid", keyId); - - Map payloadMap = new HashMap<>(); - if (StringUtils.isNotBlank(item.getUserSub())) { - payloadMap.put("sub", item.getUserSub()); - } - payloadMap.put("iat", iat); - payloadMap.put("exp", exp); - - String headerJson = JsonUtil.toJson(headerMap); - String payloadJson = JsonUtil.toJson(payloadMap); - - - String header = base64UrlEncoder.encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); - String payload = base64UrlEncoder.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); - byte[] signatureBytes = this.algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); - String signature = base64UrlEncoder.encodeToString(signatureBytes); - return String.format("%s.%s.%s", header, payload, signature); - } -} diff --git a/src/test/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeServiceTest.java b/src/test/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeServiceTest.java similarity index 85% rename from src/test/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeServiceTest.java rename to src/test/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeServiceTest.java index c832fca..bddeb29 100644 --- a/src/test/java/org/clevercastle/helper/login/oauth2/github/GithubOauth2ExchangeServiceTest.java +++ b/src/test/java/org/clevercastle/authforge/oauth2/github/GithubOauth2ExchangeServiceTest.java @@ -1,19 +1,18 @@ -package org.clevercastle.helper.login.oauth2.github; +package org.clevercastle.authforge.oauth2.github; import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.TokenResponse; import com.nimbusds.oauth2.sdk.http.HTTPRequest; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.token.AccessTokenType; -import org.clevercastle.helper.login.CastleException; -import org.clevercastle.helper.login.http.HttpRequest; -import org.clevercastle.helper.login.http.HttpResponse; -import org.clevercastle.helper.login.http.IHttpClient; -import org.clevercastle.helper.login.oauth2.Oauth2ClientConfig; +import org.clevercastle.authforge.CastleException; +import org.clevercastle.authforge.http.HttpRequest; +import org.clevercastle.authforge.http.HttpResponse; +import org.clevercastle.authforge.http.IHttpClient; +import org.clevercastle.authforge.oauth2.Oauth2ClientConfig; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.net.http.HttpClient; import java.util.List; public class GithubOauth2ExchangeServiceTest { diff --git a/src/test/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeServiceTest.java b/src/test/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeServiceTest.java new file mode 100644 index 0000000..733ba44 --- /dev/null +++ b/src/test/java/org/clevercastle/authforge/oauth2/oidc/OidcExchangeServiceTest.java @@ -0,0 +1,4 @@ +package org.clevercastle.authforge.oauth2.oidc; + +public class OidcExchangeServiceTest { +} diff --git a/src/test/java/org/clevercastle/helper/login/util/CryptoUtilTest.java b/src/test/java/org/clevercastle/authforge/util/CryptoUtilTest.java similarity index 98% rename from src/test/java/org/clevercastle/helper/login/util/CryptoUtilTest.java rename to src/test/java/org/clevercastle/authforge/util/CryptoUtilTest.java index 4e8c660..076180a 100644 --- a/src/test/java/org/clevercastle/helper/login/util/CryptoUtilTest.java +++ b/src/test/java/org/clevercastle/authforge/util/CryptoUtilTest.java @@ -1,6 +1,6 @@ -package org.clevercastle.helper.login.util; +package org.clevercastle.authforge.util; -import org.clevercastle.helper.login.CastleException; +import org.clevercastle.authforge.CastleException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; diff --git a/src/test/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeServiceTest.java b/src/test/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeServiceTest.java deleted file mode 100644 index 4061717..0000000 --- a/src/test/java/org/clevercastle/helper/login/oauth2/oidc/OidcExchangeServiceTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.clevercastle.helper.login.oauth2.oidc; - -public class OidcExchangeServiceTest { -}