forked from Baeldung/spring-security-oauth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Baeldung#203 from sampada07/JAVA-409
JAVA-409: Update SSO with OAuth2 article
- Loading branch information
Showing
51 changed files
with
3,564 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
## Spring Security OAuth - Dynamic Client Registration | ||
|
||
### Relevant information: | ||
|
||
1. `sso-authorization-server` is a Keycloak Authorization Server wrapped as a Spring Boot application | ||
2. There is one OAuth Client registered in the Authorization Server: | ||
1. Client Id: ssoClient | ||
2. Client secret: ssoClientSecret | ||
3. Redirect Uri: http://localhost:8089/ | ||
3. `sso-resource-server` is a Spring Boot based RESTFul API, acting as a backend Application | ||
4. `sso-client-app-1` and `sso-client-app-2` are two identical Spring MVC Thymeleaf App acting our front end. They are available at [http://localhost:8082/ui-one/](http://localhost:8082/ui-one) and [http://localhost:8084/ui-two/](http://localhost:8084/ui-two/) respectively. | ||
5. There are two users registered in the Authorization Server: | ||
1. [email protected] / 123 | ||
2. [email protected] / pass | ||
|
||
## Relevant Articles: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<description>New OAuth2 Stack in Spring Security 5</description> | ||
|
||
<groupId>com.baeldung</groupId> | ||
<artifactId>oauth-sso</artifactId> | ||
<version>0.1.0-SNAPSHOT</version> | ||
<packaging>pom</packaging> | ||
|
||
<modules> | ||
<module>sso-authorization-server</module> | ||
<module>sso-resource-server</module> | ||
<module>sso-client-app-1</module> | ||
<module>sso-client-app-2</module> | ||
</modules> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>com.baeldung</groupId> | ||
<artifactId>sso-authorization-server</artifactId> | ||
<version>0.1.0-SNAPSHOT</version> | ||
<packaging>jar</packaging> | ||
|
||
<parent> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>2.2.6.RELEASE</version> | ||
<relativePath /> | ||
</parent> | ||
|
||
<dependencies> | ||
|
||
<!-- web --> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-actuator</artifactId> | ||
</dependency> | ||
|
||
<!-- persistence --> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-jpa</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.h2database</groupId> | ||
<artifactId>h2</artifactId> | ||
<scope>runtime</scope> | ||
</dependency> | ||
|
||
<!-- Keycloak server --> | ||
|
||
<dependency> | ||
<groupId>org.jboss.resteasy</groupId> | ||
<artifactId>resteasy-jackson2-provider</artifactId> | ||
<version>${resteasy.version}</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-dependencies-server-all</artifactId> | ||
<version>${keycloak.version}</version> | ||
<type>pom</type> | ||
</dependency> | ||
|
||
<!-- config properties processor --> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-configuration-processor</artifactId> | ||
<optional>true</optional> | ||
</dependency> | ||
|
||
<!-- test --> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.rest-assured</groupId> | ||
<artifactId>rest-assured</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<configuration> | ||
<excludes> | ||
<exclude>**/*LiveTest.java</exclude> | ||
</excludes> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<developers> | ||
<developer> | ||
<email>[email protected]</email> | ||
<name>Eugen Paraschiv</name> | ||
<url>https://github.com/eugenp</url> | ||
<id>eugenp</id> | ||
</developer> | ||
</developers> | ||
|
||
<properties> | ||
<!-- non-dependencies --> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<java.version>13</java.version> | ||
|
||
<keycloak.version>10.0.1</keycloak.version> | ||
<resteasy.version>3.11.2.Final</resteasy.version> | ||
</properties> | ||
|
||
</project> |
39 changes: 39 additions & 0 deletions
39
...-sso/sso-authorization-server/src/main/java/com/baeldung/auth/AuthorizationServerApp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.baeldung.auth; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; | ||
import org.springframework.boot.autoconfigure.web.ServerProperties; | ||
import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.ApplicationListener; | ||
import org.springframework.context.annotation.Bean; | ||
|
||
import com.baeldung.auth.config.KeycloakServerProperties; | ||
|
||
@SpringBootApplication(exclude = LiquibaseAutoConfiguration.class) | ||
@EnableConfigurationProperties({ KeycloakServerProperties.class }) | ||
public class AuthorizationServerApp { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(AuthorizationServerApp.class); | ||
|
||
public static void main(String[] args) throws Exception { | ||
SpringApplication.run(AuthorizationServerApp.class, args); | ||
} | ||
|
||
@Bean | ||
ApplicationListener<ApplicationReadyEvent> onApplicationReadyEventListener(ServerProperties serverProperties, | ||
KeycloakServerProperties keycloakServerProperties) { | ||
|
||
return (evt) -> { | ||
|
||
Integer port = serverProperties.getPort(); | ||
String keycloakContextPath = keycloakServerProperties.getContextPath(); | ||
|
||
LOG.info("Embedded Keycloak started: http://localhost:{}{} to use keycloak", port, keycloakContextPath); | ||
}; | ||
} | ||
|
||
} |
81 changes: 81 additions & 0 deletions
81
...horization-server/src/main/java/com/baeldung/auth/config/EmbeddedKeycloakApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.baeldung.auth.config; | ||
|
||
import java.util.NoSuchElementException; | ||
|
||
import org.keycloak.Config; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.representations.idm.RealmRepresentation; | ||
import org.keycloak.services.managers.ApplianceBootstrap; | ||
import org.keycloak.services.managers.RealmManager; | ||
import org.keycloak.services.resources.KeycloakApplication; | ||
import org.keycloak.services.util.JsonConfigProviderFactory; | ||
import org.keycloak.util.JsonSerialization; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.core.io.ClassPathResource; | ||
import org.springframework.core.io.Resource; | ||
|
||
import com.baeldung.auth.config.KeycloakServerProperties.AdminUser; | ||
|
||
public class EmbeddedKeycloakApplication extends KeycloakApplication { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(EmbeddedKeycloakApplication.class); | ||
|
||
static KeycloakServerProperties keycloakServerProperties; | ||
|
||
protected void loadConfig() { | ||
JsonConfigProviderFactory factory = new RegularJsonConfigProviderFactory(); | ||
Config.init(factory.create() | ||
.orElseThrow(() -> new NoSuchElementException("No value present"))); | ||
} | ||
|
||
public EmbeddedKeycloakApplication() { | ||
|
||
super(); | ||
|
||
createMasterRealmAdminUser(); | ||
|
||
createBaeldungRealm(); | ||
} | ||
|
||
private void createMasterRealmAdminUser() { | ||
|
||
KeycloakSession session = getSessionFactory().create(); | ||
|
||
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session); | ||
|
||
AdminUser admin = keycloakServerProperties.getAdminUser(); | ||
|
||
try { | ||
session.getTransactionManager().begin(); | ||
applianceBootstrap.createMasterRealmUser(admin.getUsername(), admin.getPassword()); | ||
session.getTransactionManager().commit(); | ||
} catch (Exception ex) { | ||
LOG.warn("Couldn't create keycloak master admin user: {}", ex.getMessage()); | ||
session.getTransactionManager().rollback(); | ||
} | ||
|
||
session.close(); | ||
} | ||
|
||
private void createBaeldungRealm() { | ||
KeycloakSession session = getSessionFactory().create(); | ||
|
||
try { | ||
session.getTransactionManager().begin(); | ||
|
||
RealmManager manager = new RealmManager(session); | ||
Resource lessonRealmImportFile = new ClassPathResource(keycloakServerProperties.getRealmImportFile()); | ||
|
||
manager.importRealm( | ||
JsonSerialization.readValue(lessonRealmImportFile.getInputStream(), RealmRepresentation.class)); | ||
|
||
session.getTransactionManager().commit(); | ||
} catch (Exception ex) { | ||
LOG.warn("Failed to import Realm json file: {}", ex.getMessage()); | ||
session.getTransactionManager().rollback(); | ||
} | ||
|
||
session.close(); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
...o-authorization-server/src/main/java/com/baeldung/auth/config/EmbeddedKeycloakConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.baeldung.auth.config; | ||
|
||
import javax.naming.CompositeName; | ||
import javax.naming.InitialContext; | ||
import javax.naming.Name; | ||
import javax.naming.NameParser; | ||
import javax.naming.NamingException; | ||
import javax.naming.spi.NamingManager; | ||
import javax.sql.DataSource; | ||
|
||
import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher; | ||
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters; | ||
import org.keycloak.services.filters.KeycloakSessionServletFilter; | ||
import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
import org.springframework.boot.web.servlet.ServletRegistrationBean; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class EmbeddedKeycloakConfig { | ||
|
||
@Bean | ||
ServletRegistrationBean<HttpServlet30Dispatcher> keycloakJaxRsApplication( | ||
KeycloakServerProperties keycloakServerProperties, DataSource dataSource) throws Exception { | ||
|
||
mockJndiEnvironment(dataSource); | ||
EmbeddedKeycloakApplication.keycloakServerProperties = keycloakServerProperties; | ||
|
||
ServletRegistrationBean<HttpServlet30Dispatcher> servlet = new ServletRegistrationBean<>( | ||
new HttpServlet30Dispatcher()); | ||
servlet.addInitParameter("javax.ws.rs.Application", EmbeddedKeycloakApplication.class.getName()); | ||
servlet.addInitParameter(ResteasyContextParameters.RESTEASY_SERVLET_MAPPING_PREFIX, | ||
keycloakServerProperties.getContextPath()); | ||
servlet.addInitParameter(ResteasyContextParameters.RESTEASY_USE_CONTAINER_FORM_PARAMS, "true"); | ||
servlet.addUrlMappings(keycloakServerProperties.getContextPath() + "/*"); | ||
servlet.setLoadOnStartup(1); | ||
servlet.setAsyncSupported(true); | ||
|
||
return servlet; | ||
} | ||
|
||
@Bean | ||
FilterRegistrationBean<KeycloakSessionServletFilter> keycloakSessionManagement( | ||
KeycloakServerProperties keycloakServerProperties) { | ||
|
||
FilterRegistrationBean<KeycloakSessionServletFilter> filter = new FilterRegistrationBean<>(); | ||
filter.setName("Keycloak Session Management"); | ||
filter.setFilter(new KeycloakSessionServletFilter()); | ||
filter.addUrlPatterns(keycloakServerProperties.getContextPath() + "/*"); | ||
|
||
return filter; | ||
} | ||
|
||
private void mockJndiEnvironment(DataSource dataSource) throws NamingException { | ||
NamingManager.setInitialContextFactoryBuilder((env) -> (environment) -> new InitialContext() { | ||
|
||
@Override | ||
public Object lookup(Name name) { | ||
return lookup(name.toString()); | ||
} | ||
|
||
@Override | ||
public Object lookup(String name) { | ||
|
||
if ("spring/datasource".equals(name)) { | ||
return dataSource; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
@Override | ||
public NameParser getNameParser(String name) { | ||
return CompositeName::new; | ||
} | ||
|
||
@Override | ||
public void close() { | ||
// NOOP | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.