-
-
Notifications
You must be signed in to change notification settings - Fork 217
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 #443 from pblanchardie/270-add-spring-security-oauth2
Spring Boot Security: OAuth 2.0 and OpenID Connect
- Loading branch information
Showing
45 changed files
with
4,703 additions
and
5 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 |
---|---|---|
|
@@ -103,6 +103,7 @@ jobs: | |
matrix: | ||
app: | ||
- fullapp | ||
- oauth2app | ||
- mysqlapp | ||
- mariadbapp | ||
- flywayapp | ||
|
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
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
55 changes: 55 additions & 0 deletions
55
...e/generator/server/springboot/mvc/security/common/domain/CommonSecurityDomainService.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,55 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.common.domain; | ||
|
||
import static tech.jhipster.lite.common.domain.FileUtils.getPath; | ||
import static tech.jhipster.lite.generator.project.domain.Constants.MAIN_JAVA; | ||
import static tech.jhipster.lite.generator.project.domain.Constants.TEST_JAVA; | ||
import static tech.jhipster.lite.generator.project.domain.DefaultConfig.PACKAGE_PATH; | ||
|
||
import tech.jhipster.lite.generator.project.domain.Project; | ||
import tech.jhipster.lite.generator.project.domain.ProjectRepository; | ||
|
||
public class CommonSecurityDomainService implements CommonSecurityService { | ||
|
||
private final ProjectRepository projectRepository; | ||
|
||
public CommonSecurityDomainService(ProjectRepository projectRepository) { | ||
this.projectRepository = projectRepository; | ||
} | ||
|
||
@Override | ||
public void updateExceptionTranslator(Project project) { | ||
String packageNamePath = project.getPackageNamePath().orElse(getPath(PACKAGE_PATH)); | ||
String exceptionTranslatorPath = getPath(MAIN_JAVA, packageNamePath, "technical/infrastructure/primary/exception"); | ||
String exceptionTranslatorFile = "ExceptionTranslator.java"; | ||
|
||
String oldImport = "import org.zalando.problem.spring.web.advice.ProblemHandling;"; | ||
String newImport = | ||
""" | ||
import org.zalando.problem.spring.web.advice.ProblemHandling; | ||
import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait;"""; | ||
projectRepository.replaceText(project, exceptionTranslatorPath, exceptionTranslatorFile, oldImport, newImport); | ||
|
||
String oldImplements = "public class ExceptionTranslator implements ProblemHandling \\{"; | ||
String newImplements = "public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait \\{"; | ||
projectRepository.replaceText(project, exceptionTranslatorPath, exceptionTranslatorFile, oldImplements, newImplements); | ||
} | ||
|
||
@Override | ||
public void updateIntegrationTestWithMockUser(Project project) { | ||
String packageNamePath = project.getPackageNamePath().orElse(getPath(PACKAGE_PATH)); | ||
String integrationTestPath = getPath(TEST_JAVA, packageNamePath); | ||
|
||
String oldImport = "import org.springframework.boot.test.context.SpringBootTest;"; | ||
String newImport = | ||
""" | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.security.test.context.support.WithMockUser;"""; | ||
projectRepository.replaceText(project, integrationTestPath, "IntegrationTest.java", oldImport, newImport); | ||
|
||
String oldAnnotation = "public @interface"; | ||
String newAnnotation = """ | ||
@WithMockUser | ||
public @interface"""; | ||
projectRepository.replaceText(project, integrationTestPath, "IntegrationTest.java", oldAnnotation, newAnnotation); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...er/lite/generator/server/springboot/mvc/security/common/domain/CommonSecurityService.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,8 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.common.domain; | ||
|
||
import tech.jhipster.lite.generator.project.domain.Project; | ||
|
||
public interface CommonSecurityService { | ||
void updateExceptionTranslator(Project project); | ||
void updateIntegrationTestWithMockUser(Project project); | ||
} |
22 changes: 22 additions & 0 deletions
22
...springboot/mvc/security/common/infrastructure/config/CommonSecurityBeanConfiguration.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,22 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.common.infrastructure.config; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import tech.jhipster.lite.generator.project.domain.ProjectRepository; | ||
import tech.jhipster.lite.generator.server.springboot.mvc.security.common.domain.CommonSecurityDomainService; | ||
import tech.jhipster.lite.generator.server.springboot.mvc.security.common.domain.CommonSecurityService; | ||
|
||
@Configuration | ||
public class CommonSecurityBeanConfiguration { | ||
|
||
private final ProjectRepository projectRepository; | ||
|
||
public CommonSecurityBeanConfiguration(ProjectRepository projectRepository) { | ||
this.projectRepository = projectRepository; | ||
} | ||
|
||
@Bean | ||
public CommonSecurityService commonSecurityService() { | ||
return new CommonSecurityDomainService(projectRepository); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
...java/tech/jhipster/lite/generator/server/springboot/mvc/security/common/package-info.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,2 @@ | ||
@tech.jhipster.lite.SharedKernel | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.common; |
19 changes: 19 additions & 0 deletions
19
...r/server/springboot/mvc/security/oauth2/application/OAuth2SecurityApplicationService.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,19 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.application; | ||
|
||
import org.springframework.stereotype.Service; | ||
import tech.jhipster.lite.generator.project.domain.Project; | ||
import tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.domain.OAuth2SecurityService; | ||
|
||
@Service | ||
public class OAuth2SecurityApplicationService { | ||
|
||
private final OAuth2SecurityService oauth2SecurityService; | ||
|
||
public OAuth2SecurityApplicationService(OAuth2SecurityService oauth2SecurityService) { | ||
this.oauth2SecurityService = oauth2SecurityService; | ||
} | ||
|
||
public void addOAuth2(Project project) { | ||
oauth2SecurityService.addOAuth2(project); | ||
} | ||
} |
106 changes: 106 additions & 0 deletions
106
.../jhipster/lite/generator/server/springboot/mvc/security/oauth2/domain/OAuth2Security.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,106 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.domain; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import tech.jhipster.lite.generator.buildtool.generic.domain.Dependency; | ||
|
||
public class OAuth2Security { | ||
|
||
private static final String INFRASTRUCTURE_CONFIG = "infrastructure/config"; | ||
|
||
private static final String DOCKER_KEYCLOAK_IMAGE = "jboss/keycloak"; | ||
private static final String DOCKER_KEYCLOAK_VERSION = "16.1.0"; | ||
|
||
private static final String SPRINGBOOT_PACKAGE = "org.springframework.boot"; | ||
|
||
private static final String STARTER_SECURITY = "spring-boot-starter-security"; | ||
private static final String STARTER_OAUTH2_CLIENT = "spring-boot-starter-oauth2-client"; | ||
private static final String STARTER_OAUTH2_RESOURCE_SERVER = "spring-boot-starter-oauth2-resource-server"; | ||
|
||
private OAuth2Security() {} | ||
|
||
public static String getDockerKeycloakImage() { | ||
return DOCKER_KEYCLOAK_IMAGE + ":" + DOCKER_KEYCLOAK_VERSION; | ||
} | ||
|
||
public static String getDockerKeycloakVersion() { | ||
return DOCKER_KEYCLOAK_VERSION; | ||
} | ||
|
||
public static Dependency springBootStarterSecurityDependency() { | ||
return Dependency.builder().groupId(SPRINGBOOT_PACKAGE).artifactId(STARTER_SECURITY).build(); | ||
} | ||
|
||
public static Dependency springBootStarterOAuth2ClientDependency() { | ||
return Dependency.builder().groupId(SPRINGBOOT_PACKAGE).artifactId(STARTER_OAUTH2_CLIENT).build(); | ||
} | ||
|
||
public static Dependency springBootStarterOAuth2ResourceServerDependency() { | ||
return Dependency.builder().groupId(SPRINGBOOT_PACKAGE).artifactId(STARTER_OAUTH2_RESOURCE_SERVER).build(); | ||
} | ||
|
||
public static Dependency springSecurityTestDependency() { | ||
return Dependency.builder().groupId("org.springframework.security").artifactId("spring-security-test").scope("test").build(); | ||
} | ||
|
||
public static Map<String, String> oauth2SecurityFiles() { | ||
Map<String, String> map = new HashMap<>(); | ||
|
||
map.put("SecurityUtils.java", "application"); | ||
|
||
map.put("AuthoritiesConstants.java", "domain"); | ||
map.put("ApplicationSecurityDefaults.java", "domain"); | ||
|
||
map.put("ApplicationSecurityProperties.java", INFRASTRUCTURE_CONFIG); | ||
map.put("AudienceValidator.java", INFRASTRUCTURE_CONFIG); | ||
map.put("CustomClaimConverter.java", INFRASTRUCTURE_CONFIG); | ||
map.put("JwtGrantedAuthorityConverter.java", INFRASTRUCTURE_CONFIG); | ||
map.put("OAuth2Configuration.java", INFRASTRUCTURE_CONFIG); | ||
map.put("SecurityConfiguration.java", INFRASTRUCTURE_CONFIG); | ||
|
||
return map; | ||
} | ||
|
||
public static Map<String, String> oauth2TestSecurityFiles() { | ||
Map<String, String> map = new HashMap<>(); | ||
|
||
map.put("SecurityUtilsTest.java", "application"); | ||
|
||
map.put("ApplicationSecurityPropertiesTest.java", INFRASTRUCTURE_CONFIG); | ||
map.put("AudienceValidatorTest.java", INFRASTRUCTURE_CONFIG); | ||
map.put("CustomClaimConverterIT.java", INFRASTRUCTURE_CONFIG); | ||
map.put("FakeRequestAttributes.java", INFRASTRUCTURE_CONFIG); | ||
map.put("JwtGrantedAuthorityConverterTest.java", INFRASTRUCTURE_CONFIG); | ||
map.put("SecurityConfigurationIT.java", INFRASTRUCTURE_CONFIG); | ||
map.put("SecurityConfigurationTest.java", INFRASTRUCTURE_CONFIG); | ||
map.put("TestSecurityConfiguration.java", INFRASTRUCTURE_CONFIG); | ||
|
||
map.put("WithUnauthenticatedMockUser.java", "infrastructure"); | ||
|
||
return map; | ||
} | ||
|
||
public static Map<String, String> properties() { | ||
return Map.of( | ||
"spring.security.oauth2.client.provider.oidc.issuer-uri", | ||
"http://localhost:9080/auth/realms/jhipster", | ||
"spring.security.oauth2.client.registration.oidc.client-id", | ||
"web_app", | ||
"spring.security.oauth2.client.registration.oidc.client-secret", | ||
"web_app", | ||
"spring.security.oauth2.client.registration.oidc.scope", | ||
"openid,profile,email", | ||
"application.security.oauth2.audience", | ||
"account,api://default" | ||
); | ||
} | ||
|
||
public static Map<String, String> propertiesForTests() { | ||
return Map.of( | ||
"spring.main.allow-bean-definition-overriding", | ||
"true", | ||
"spring.security.oauth2.client.provider.oidc.issuer-uri", | ||
"http://DO_NOT_CALL:9080/auth/realms/jhipster" | ||
); | ||
} | ||
} |
127 changes: 127 additions & 0 deletions
127
...e/generator/server/springboot/mvc/security/oauth2/domain/OAuth2SecurityDomainService.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,127 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.domain; | ||
|
||
import static tech.jhipster.lite.common.domain.FileUtils.getPath; | ||
import static tech.jhipster.lite.generator.project.domain.Constants.*; | ||
import static tech.jhipster.lite.generator.project.domain.DefaultConfig.*; | ||
import static tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.domain.OAuth2Security.*; | ||
|
||
import tech.jhipster.lite.common.domain.WordUtils; | ||
import tech.jhipster.lite.generator.buildtool.generic.domain.BuildToolService; | ||
import tech.jhipster.lite.generator.project.domain.Project; | ||
import tech.jhipster.lite.generator.project.domain.ProjectRepository; | ||
import tech.jhipster.lite.generator.server.springboot.common.domain.SpringBootCommonService; | ||
import tech.jhipster.lite.generator.server.springboot.mvc.security.common.domain.CommonSecurityService; | ||
|
||
public class OAuth2SecurityDomainService implements OAuth2SecurityService { | ||
|
||
public static final String SOURCE = "server/springboot/mvc/security/oauth2"; | ||
public static final String SECURITY_OAUTH2_PATH = "security/oauth2"; | ||
|
||
private final ProjectRepository projectRepository; | ||
private final BuildToolService buildToolService; | ||
private final SpringBootCommonService springBootCommonService; | ||
private final CommonSecurityService commonSecurityService; | ||
|
||
public OAuth2SecurityDomainService( | ||
ProjectRepository projectRepository, | ||
BuildToolService buildToolService, | ||
SpringBootCommonService springBootCommonService, | ||
CommonSecurityService commonSecurityService | ||
) { | ||
this.projectRepository = projectRepository; | ||
this.buildToolService = buildToolService; | ||
this.springBootCommonService = springBootCommonService; | ||
this.commonSecurityService = commonSecurityService; | ||
} | ||
|
||
@Override | ||
public void addOAuth2(Project project) { | ||
addDependencies(project); | ||
addKeycloakDocker(project); | ||
addJavaFiles(project); | ||
addSpringBootProperties(project); | ||
|
||
updateExceptionTranslator(project); | ||
updateIntegrationTestWithMockUser(project); | ||
updateIntegrationTestWithTestSecurityConfiguration(project); | ||
} | ||
|
||
private void addDependencies(Project project) { | ||
buildToolService.addDependency(project, springBootStarterSecurityDependency()); | ||
buildToolService.addDependency(project, springBootStarterOAuth2ClientDependency()); | ||
buildToolService.addDependency(project, springSecurityTestDependency()); | ||
buildToolService.addDependency(project, springBootStarterOAuth2ResourceServerDependency()); | ||
} | ||
|
||
private void addKeycloakDocker(Project project) { | ||
project.addConfig("dockerKeycloakImage", getDockerKeycloakImage()); | ||
project.addConfig("dockerKeycloakVersion", getDockerKeycloakVersion()); | ||
|
||
String dockerSourcePath = getPath(SOURCE, "docker"); | ||
String dockerPathRealm = getPath(MAIN_DOCKER, "keycloak-realm-config"); | ||
projectRepository.template(project, dockerSourcePath, "keycloak.yml", MAIN_DOCKER, "keycloak.yml"); | ||
projectRepository.template(project, dockerSourcePath, "jhipster-realm.json", dockerPathRealm, "jhipster-realm.json"); | ||
projectRepository.template(project, dockerSourcePath, "jhipster-users-0.json", dockerPathRealm, "jhipster-users-0.json"); | ||
} | ||
|
||
private void addJavaFiles(Project project) { | ||
project.addDefaultConfig(PACKAGE_NAME); | ||
String packageNamePath = project.getPackageNamePath().orElse(getPath(PACKAGE_PATH)); | ||
|
||
String sourceSrc = getPath(SOURCE, "src"); | ||
String destinationSrc = getPath(MAIN_JAVA, packageNamePath, SECURITY_OAUTH2_PATH); | ||
oauth2SecurityFiles() | ||
.forEach((javaFile, folder) -> | ||
projectRepository.template(project, getPath(sourceSrc, folder), javaFile, getPath(destinationSrc, folder)) | ||
); | ||
|
||
String sourceTest = getPath(SOURCE, "test"); | ||
String destinationTest = getPath(TEST_JAVA, packageNamePath, SECURITY_OAUTH2_PATH); | ||
oauth2TestSecurityFiles() | ||
.forEach((javaFile, folder) -> | ||
projectRepository.template(project, getPath(sourceTest, folder), javaFile, getPath(destinationTest, folder)) | ||
); | ||
} | ||
|
||
private void addSpringBootProperties(Project project) { | ||
springBootCommonService.addPropertiesComment(project, "Spring Security OAuth2"); | ||
properties().forEach((k, v) -> springBootCommonService.addProperties(project, k, v)); | ||
springBootCommonService.addPropertiesNewLine(project); | ||
|
||
springBootCommonService.addPropertiesTestComment(project, "Spring Security OAuth2"); | ||
propertiesForTests().forEach((k, v) -> springBootCommonService.addPropertiesTest(project, k, v)); | ||
springBootCommonService.addPropertiesTestNewLine(project); | ||
} | ||
|
||
private void updateExceptionTranslator(Project project) { | ||
commonSecurityService.updateExceptionTranslator(project); | ||
} | ||
|
||
private void updateIntegrationTestWithMockUser(Project project) { | ||
commonSecurityService.updateIntegrationTestWithMockUser(project); | ||
} | ||
|
||
private void updateIntegrationTestWithTestSecurityConfiguration(Project project) { | ||
project.addDefaultConfig(PACKAGE_NAME); | ||
String packageName = project.getPackageName().orElse(DEFAULT_PACKAGE_NAME); | ||
String packageNamePath = project.getPackageNamePath().orElse(getPath(PACKAGE_PATH)); | ||
String integrationTestPath = getPath(TEST_JAVA, packageNamePath); | ||
|
||
project.addDefaultConfig(BASE_NAME); | ||
String baseName = project.getBaseName().orElse(DEFAULT_BASE_NAME); | ||
String className = WordUtils.upperFirst(baseName); | ||
|
||
String oldImport = "import org.springframework.boot.test.context.SpringBootTest;"; | ||
String newImport = String.format( | ||
""" | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import %s.security.oauth2.infrastructure.config.TestSecurityConfiguration;""", | ||
packageName | ||
); | ||
projectRepository.replaceText(project, integrationTestPath, "IntegrationTest.java", oldImport, newImport); | ||
|
||
String oldClass = className + "App.class"; | ||
String newClass = className + "App.class, TestSecurityConfiguration.class"; | ||
projectRepository.replaceText(project, integrationTestPath, "IntegrationTest.java", oldClass, newClass); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
...er/lite/generator/server/springboot/mvc/security/oauth2/domain/OAuth2SecurityService.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,7 @@ | ||
package tech.jhipster.lite.generator.server.springboot.mvc.security.oauth2.domain; | ||
|
||
import tech.jhipster.lite.generator.project.domain.Project; | ||
|
||
public interface OAuth2SecurityService { | ||
void addOAuth2(Project project); | ||
} |
Oops, something went wrong.