Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
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;
import org.springframework.web.bind.annotation.RequestHeader;
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;

Expand Down Expand Up @@ -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("<UNK>");
}
userService.getByLoginIdentifier(userSub);
Pair<User, UserLoginItem> pair = userService.getByUserSub(userSub);
if (pair.getLeft() == null || pair.getRight() == null) {
throw new CastleException("<UNK>");
}
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.clevercastle.authforge.examples.springboot.springbootexample;

public enum SsoType {
github,
google
}
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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<UserRefreshTokenMapping, UserRefreshTokenMappingId> {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

public class CastleException extends Exception {
public CastleException() {
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/org/clevercastle/authforge/Config.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

import jakarta.annotation.Nonnull;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

import java.time.OffsetDateTime;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -24,8 +24,6 @@ public class User {
private String resetPasswordCode;
private OffsetDateTime resetPasswordCodeExpiredAt;

// private Set<RefreshToken> refreshTokens;

private OffsetDateTime createdAt;
private OffsetDateTime updatedAt;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.clevercastle.helper.login;
package org.clevercastle.authforge;

public class UserRegisterRequest {
private String loginIdentifier;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -11,10 +11,14 @@ public interface UserService {

UserWithToken login(String loginIdentifier, String password) throws CastleException;

Pair<User, UserLoginItem> get(String loginIdentifier) throws CastleException;
Pair<User, UserLoginItem> getByLoginIdentifier(String loginIdentifier) throws CastleException;

Pair<User, UserLoginItem> 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;
}
Loading
Loading