diff --git a/src/main/java/com/heaerie/server/auth201/Auth201Server/config/OAuth2SecurityConfig.java b/src/main/java/com/heaerie/server/auth201/Auth201Server/config/OAuth2SecurityConfig.java index b5688de..a39b690 100644 --- a/src/main/java/com/heaerie/server/auth201/Auth201Server/config/OAuth2SecurityConfig.java +++ b/src/main/java/com/heaerie/server/auth201/Auth201Server/config/OAuth2SecurityConfig.java @@ -75,7 +75,7 @@ public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize - .requestMatchers("/", "/authorized", "/logged-out", "/h2-console/**", "/error").permitAll() + .requestMatchers("/", "/authorized", "/logged-out", "/h2-console/**", "/error", "/oauth/register", "/test-client.html").permitAll() .anyRequest().authenticated() ) .formLogin(form -> form diff --git a/src/main/java/com/heaerie/server/auth201/Auth201Server/controller/ClientRegistrationController.java b/src/main/java/com/heaerie/server/auth201/Auth201Server/controller/ClientRegistrationController.java new file mode 100644 index 0000000..a88544f --- /dev/null +++ b/src/main/java/com/heaerie/server/auth201/Auth201Server/controller/ClientRegistrationController.java @@ -0,0 +1,64 @@ +package com.heaerie.server.auth201.Auth201Server.controller; + +import com.heaerie.server.auth201.Auth201Server.dto.ClientRegistrationRequest; +import com.heaerie.server.auth201.Auth201Server.dto.ClientRegistrationResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@Controller +@RequestMapping("/oauth") +public class ClientRegistrationController { + + private final PasswordEncoder passwordEncoder; + + public ClientRegistrationController(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + @GetMapping("/register") + public String showRegistrationForm() { + return "register-client"; + } + + @PostMapping("/register") + @ResponseBody + public ResponseEntity registerClient(@RequestBody ClientRegistrationRequest request) { + // Generate client ID + String clientId = generateClientId(request.getClientName()); + + // Generate client secret for confidential clients + String clientSecret = null; + if ("confidential".equals(request.getClientType())) { + clientSecret = generateClientSecret(); + } + + ClientRegistrationResponse response = new ClientRegistrationResponse(); + response.setClientId(clientId); + response.setClientSecret(clientSecret); + response.setClientType(request.getClientType()); + response.setMessage("Client registered successfully"); + + return ResponseEntity.ok(response); + } + + private String generateClientId(String clientName) { + // Create a client ID based on the name and a UUID + String sanitized = clientName.toLowerCase() + .replaceAll("[^a-z0-9-]", "-") + .replaceAll("-+", "-") + .replaceAll("^-|-$", ""); + + String shortUuid = UUID.randomUUID().toString().substring(0, 8); + return sanitized + "-" + shortUuid; + } + + private String generateClientSecret() { + // Generate a secure random secret + return UUID.randomUUID().toString().replace("-", "") + + UUID.randomUUID().toString().replace("-", ""); + } +} diff --git a/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationRequest.java b/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationRequest.java new file mode 100644 index 0000000..e93b83f --- /dev/null +++ b/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationRequest.java @@ -0,0 +1,88 @@ +package com.heaerie.server.auth201.Auth201Server.dto; + +import java.util.List; + +public class ClientRegistrationRequest { + private String clientName; + private String clientType; + private String description; + private List redirectUris; + private List logoutRedirectUris; + private List grantTypes; + private List scopes; + private boolean requireConsent; + private boolean requirePkce; + + // Getters and Setters + public String getClientName() { + return clientName; + } + + public void setClientName(String clientName) { + this.clientName = clientName; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getRedirectUris() { + return redirectUris; + } + + public void setRedirectUris(List redirectUris) { + this.redirectUris = redirectUris; + } + + public List getLogoutRedirectUris() { + return logoutRedirectUris; + } + + public void setLogoutRedirectUris(List logoutRedirectUris) { + this.logoutRedirectUris = logoutRedirectUris; + } + + public List getGrantTypes() { + return grantTypes; + } + + public void setGrantTypes(List grantTypes) { + this.grantTypes = grantTypes; + } + + public List getScopes() { + return scopes; + } + + public void setScopes(List scopes) { + this.scopes = scopes; + } + + public boolean isRequireConsent() { + return requireConsent; + } + + public void setRequireConsent(boolean requireConsent) { + this.requireConsent = requireConsent; + } + + public boolean isRequirePkce() { + return requirePkce; + } + + public void setRequirePkce(boolean requirePkce) { + this.requirePkce = requirePkce; + } +} diff --git a/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationResponse.java b/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationResponse.java new file mode 100644 index 0000000..1d568a9 --- /dev/null +++ b/src/main/java/com/heaerie/server/auth201/Auth201Server/dto/ClientRegistrationResponse.java @@ -0,0 +1,41 @@ +package com.heaerie.server.auth201.Auth201Server.dto; + +public class ClientRegistrationResponse { + private String clientId; + private String clientSecret; + private String clientType; + private String message; + + // Getters and Setters + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/resources/templates/register-client.html b/src/main/resources/templates/register-client.html new file mode 100644 index 0000000..9df9f63 --- /dev/null +++ b/src/main/resources/templates/register-client.html @@ -0,0 +1,1082 @@ + + + + + + Register OAuth Client - Heaerie SSO + + + +
+
+ +

Register OAuth 2.1 Client

+

Create a new OAuth client application

+
+ +
+ Registration Failed +
+
+ +
+
✓ Client Registered Successfully!
+
+
+
Client ID
+
client-id-here
+ +
+ +
+
Configuration Summary
+
+ +
+
+
+
+ + +
+
+ +
+
📋 Before You Begin
+
+ Configure your OAuth 2.1 client settings below. Public clients (SPAs, mobile apps) don't require a client secret. + Confidential clients (server-side apps) will receive a client secret after registration. +
+
+ +
+ +
+
Basic Information
+ +
+ + +
+ A human-readable name for your application + SPA Example + Mobile Example + Server Example +
+
0 / 100
+
Please enter a valid client name
+
+ +
+ +
+
+ + +
+
+ + +
+
+
Public clients cannot securely store secrets
+
+ +
+ + +
+
+ +
+
OAuth Configuration
+ +
+ +
+ + +
+
+
Where users will be redirected after authorization
+
Please add at least one valid redirect URI
+
+ +
+ +
+ + +
+
+
Where users will be redirected after logout (optional)
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
Security Settings
+ +
+ +
Users must approve access to their data
+
+ +
+ +
Proof Key for Code Exchange - highly recommended for security
+
+ + + + +
+ +
+ + +
+
+
+ +
+
+
+ + + +