From 75a625b969d26e31e7ecc167b21ba5c51467de47 Mon Sep 17 00:00:00 2001 From: jotty Date: Sat, 26 Nov 2022 22:43:23 +0100 Subject: [PATCH] prepared, but not tested --- .classpath | 9 +-- .settings/org.eclipse.buildship.core.prefs | 11 +++ .settings/org.eclipse.wst.common.component | 20 +++-- build.gradle | 9 ++- .../camporganizer/config/SecurityConfig.java | 4 +- .../registration/KeycloakRepository.java | 81 ++++++++++++++++--- .../registration/TestKeycloakRepository.java | 28 +++++++ 7 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 src/test/java/de/jottyfan/camporganizer/module/registration/TestKeycloakRepository.java diff --git a/.classpath b/.classpath index 607b789..12704c5 100644 --- a/.classpath +++ b/.classpath @@ -6,25 +6,24 @@ + - + - - - + - + diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index e889521..e479558 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 +gradle.user.home= +java.home= +jvm.arguments= +offline.mode=false +override.workspace.settings=false +show.console.view=false +show.executions.view=false diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 59fc2ab..116cc89 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,8 +1,14 @@ - - - - - - - + + + + + + + + + + + + + diff --git a/build.gradle b/build.gradle index 35fe182..8c46b55 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'war' apply plugin: 'application' group = 'de.jottyfan.camporganizer' -version = '0.1.4' +version = '0.1.5' sourceCompatibility = 17 mainClassName = "de.jottyfan.camporganizer.Main" @@ -28,8 +28,9 @@ repositories { url "https://www.jottyfan.de/libs/" } } + ext { - set('keycloakVersion', '19.0.2') + set('keycloakVersion', '20.0.1') } war { @@ -55,6 +56,10 @@ dependencies { implementation 'org.keycloak:keycloak-spring-boot-starter' + // for using the keycloak rest interface + implementation 'org.keycloak:keycloak-admin-client:20.0.1' + implementation 'org.jboss.resteasy:resteasy-client:5.0.0.Final' + // backward compatibility until the complete registration is converted to keycloak implementation 'org.jasypt:jasypt:1.9.3' diff --git a/src/main/java/de/jottyfan/camporganizer/config/SecurityConfig.java b/src/main/java/de/jottyfan/camporganizer/config/SecurityConfig.java index e47a91b..4a2f6ab 100644 --- a/src/main/java/de/jottyfan/camporganizer/config/SecurityConfig.java +++ b/src/main/java/de/jottyfan/camporganizer/config/SecurityConfig.java @@ -58,8 +58,8 @@ public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { http.authorizeRequests() // @formatter:off .antMatchers("/dashboard/**", "/business/**", "/confirmation/**").authenticated() - .anyRequest().permitAll(); - // @formatter:on + .anyRequest().permitAll(); + // @formatter:on // http.anonymous().disable(); http.csrf().disable(); } diff --git a/src/main/java/de/jottyfan/camporganizer/module/registration/KeycloakRepository.java b/src/main/java/de/jottyfan/camporganizer/module/registration/KeycloakRepository.java index a6e35f5..5c1a638 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/registration/KeycloakRepository.java +++ b/src/main/java/de/jottyfan/camporganizer/module/registration/KeycloakRepository.java @@ -1,10 +1,23 @@ package de.jottyfan.camporganizer.module.registration; +import java.util.Collections; + +import javax.ws.rs.client.Client; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.KeycloakBuilder; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.UserRepresentation; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; + /** * * @author henkej @@ -23,6 +36,12 @@ public class KeycloakRepository { @Value("${keycloak.realm:ow}") private String keycloakRealm; + @Value("${keycloak.admin.name:admin") + private String keycloakAdminName; + + @Value("${keycloak.admin.password:password") + private String keycloakAdminPassword; + /** * get the url of the user client * @@ -37,17 +56,59 @@ public class KeycloakRepository { /** * register the login in keycloak * - * @param login - * @param password + * @param login the username + * @param password the password + * @param email the email + * @return true or false */ - public void register(String login, String password) { - // TODO: check for trailing and leading / - String registrationUrl = String.format("%s/admin/realms/%s/users", keycloakUrl, keycloakRealm); - // see - // https://www.keycloak.org/docs-api/17.0/rest-api/index.html#_users_resource - // https://canada1.discourse-cdn.com/free1/uploads/keycloak/original/2X/3/379bbfe8857de117771149174a96e4216ebe9c76.png - // TODO Auto-generated method stub - LOGGER.error("not yet implemented registration of user {} in keycloak", login); + public boolean register(String login, String password, String email) { + CredentialRepresentation passwordCredentials = new CredentialRepresentation(); + passwordCredentials.setTemporary(false); + passwordCredentials.setType(CredentialRepresentation.PASSWORD); + passwordCredentials.setValue(password); + + UserRepresentation user = new UserRepresentation(); + user.setUsername(login); + user.setEmail(email); + user.setCredentials(Collections.singletonList(passwordCredentials)); + user.setEnabled(true); + + UsersResource instance = getInstance(); + Response response = instance.create(user); + boolean result = Status.OK.equals(response.getStatusInfo()); + sendVerificationLink(login); + return result; + } + + public Client getClient() { + return new ResteasyClientBuilderImpl() + .connectionPoolSize(10) + .build(); + } + + public KeycloakBuilder getKeycloak() { + return KeycloakBuilder.builder() + .serverUrl(keycloakUrl) + .realm(keycloakRealm) + .grantType(OAuth2Constants.PASSWORD) + .username(keycloakAdminName) + .password(keycloakAdminPassword) + .clientId(keycloakClientId) + .resteasyClient(getClient()); + } + + public UsersResource getInstance() { + return getKeycloak().build().realm(keycloakRealm).users(); + } + + /** + * send a verification link for newly registered users + * + * @param userId the ID of the user + */ + public void sendVerificationLink(String userId) { + UsersResource usersResource = getInstance(); + usersResource.get(userId).sendVerifyEmail(); } } diff --git a/src/test/java/de/jottyfan/camporganizer/module/registration/TestKeycloakRepository.java b/src/test/java/de/jottyfan/camporganizer/module/registration/TestKeycloakRepository.java new file mode 100644 index 0000000..00d6514 --- /dev/null +++ b/src/test/java/de/jottyfan/camporganizer/module/registration/TestKeycloakRepository.java @@ -0,0 +1,28 @@ +package de.jottyfan.camporganizer.module.registration; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author jotty + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class TestKeycloakRepository { + + @Autowired + private KeycloakRepository repository; + + /** + * test registration + */ + @Test + public void testRegister() { + assertTrue(repository.register("Hans", "Dampf", "jottyfan@mail.de")); + } +}