This commit is contained in:
parent
68124316d0
commit
f415d99e9e
@ -18,7 +18,7 @@ apply plugin: 'war'
|
|||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
group = 'de.jottyfan.camporganizer'
|
group = 'de.jottyfan.camporganizer'
|
||||||
version = '0.3.3'
|
version = '0.3.4'
|
||||||
sourceCompatibility = 17
|
sourceCompatibility = 17
|
||||||
mainClassName = "de.jottyfan.camporganizer.Main"
|
mainClassName = "de.jottyfan.camporganizer.Main"
|
||||||
|
|
||||||
@ -56,6 +56,9 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'org.keycloak:keycloak-spring-boot-starter'
|
implementation 'org.keycloak:keycloak-spring-boot-starter'
|
||||||
|
|
||||||
|
// old login algorithm; can be removed when all accounts have moved
|
||||||
|
implementation 'org.jasypt:jasypt:1.9.3'
|
||||||
|
|
||||||
// for using the keycloak rest interface
|
// for using the keycloak rest interface
|
||||||
implementation 'org.keycloak:keycloak-admin-client:20.0.1'
|
implementation 'org.keycloak:keycloak-admin-client:20.0.1'
|
||||||
implementation 'org.jboss.resteasy:resteasy-client:5.0.0.Final'
|
implementation 'org.jboss.resteasy:resteasy-client:5.0.0.Final'
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.migration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
|
||||||
|
import org.jasypt.util.password.StrongPasswordEncryptor;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.registration.validate.UnusedUsername;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@UnusedUsername(field = "email", message = "Diese E-Mail ist als Login leider bereits vergeben. Bitte wähle eine andere.")
|
||||||
|
public class MigrationBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@NotBlank(message = "Bitte gib deinen Vornamen an.")
|
||||||
|
private String forename;
|
||||||
|
@NotBlank(message = "Bitte gib deinen Nachnamen an.")
|
||||||
|
private String surname;
|
||||||
|
@NotBlank(message = "Bitte gib deinen alten Nutzernamen an.")
|
||||||
|
private String username;
|
||||||
|
@NotBlank(message = "Bitte gib dein altes Passwort an.")
|
||||||
|
private String password;
|
||||||
|
@NotBlank(message = "Bitte gib eine E-Mail-Adresse an. Ohne kannst du deinen Zugang nicht umziehen.")
|
||||||
|
@Email(message = "Bitte gib eine gültige E-Mail-Adresse an.")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the current password fits to the encrypted one
|
||||||
|
*
|
||||||
|
* @param encryptedPassword the encrypted password from the database
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
public boolean checkPassword(String encryptedPassword) {
|
||||||
|
try {
|
||||||
|
return new StrongPasswordEncryptor().checkPassword(password, encryptedPassword);
|
||||||
|
} catch (EncryptionOperationNotPossibleException e) {
|
||||||
|
return false; // password is not decryptable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the username
|
||||||
|
*/
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param username the username to set
|
||||||
|
*/
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the password
|
||||||
|
*/
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param password the password to set
|
||||||
|
*/
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the email
|
||||||
|
*/
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param email the email to set
|
||||||
|
*/
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the forename
|
||||||
|
*/
|
||||||
|
public String getForename() {
|
||||||
|
return forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param forename the forename to set
|
||||||
|
*/
|
||||||
|
public void setForename(String forename) {
|
||||||
|
this.forename = forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the surname
|
||||||
|
*/
|
||||||
|
public String getSurname() {
|
||||||
|
return surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param surname the surname to set
|
||||||
|
*/
|
||||||
|
public void setSurname(String surname) {
|
||||||
|
this.surname = surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.migration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class MigrationController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MigrationService service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* to the login page
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/migration/login")
|
||||||
|
public String getLogin(Model model) {
|
||||||
|
model.addAttribute("bean", new MigrationBean());
|
||||||
|
return "/migration/login";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/migration/loginold")
|
||||||
|
public String loginOld(@Valid @ModelAttribute("bean") MigrationBean bean, final BindingResult bindingResult, Model model) {
|
||||||
|
if (bindingResult.hasErrors()) {
|
||||||
|
return "/migration/login";
|
||||||
|
} else if (service.checkLogin(bean)) {
|
||||||
|
service.migrate(bean);
|
||||||
|
return "redirect:/dashboard";
|
||||||
|
} else {
|
||||||
|
bindingResult.addError(new FieldError("password", "password", "Dein Passwort scheint falsch zu sein, oder den Benutzer gibt es nicht."));
|
||||||
|
return "/migration/login";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.migration;
|
||||||
|
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.Record1;
|
||||||
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class MigrationRepository {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(MigrationRepository.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the encrypted password of username
|
||||||
|
*
|
||||||
|
* @param username the username
|
||||||
|
* @return the encrypted password or null
|
||||||
|
*/
|
||||||
|
public String getEncryptedPassword(String username) {
|
||||||
|
SelectConditionStep<Record1<String>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_PROFILE.PASSWORD)
|
||||||
|
.from(T_PROFILE)
|
||||||
|
.where(T_PROFILE.USERNAME.eq(username));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
return sql.fetchOne(T_PROFILE.PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.migration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.registration.KeycloakRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MigrationService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MigrationRepository repository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private KeycloakRepository keycloak;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the login is valid
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
public boolean checkLogin(@Valid MigrationBean bean) {
|
||||||
|
String encryptedPassword = repository.getEncryptedPassword(bean.getUsername());
|
||||||
|
return bean.checkPassword(encryptedPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do the migration
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
public boolean migrate(@Valid MigrationBean bean) {
|
||||||
|
return keycloak.register(bean.getForename(), bean.getSurname(), bean.getUsername(), bean.getPassword(), bean.getEmail());
|
||||||
|
}
|
||||||
|
}
|
@ -395,4 +395,10 @@ div {
|
|||||||
padding: 6px;
|
padding: 6px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block660 {
|
||||||
|
max-width: 660px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
@ -16,10 +16,14 @@
|
|||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="content">
|
<th:block layout:fragment="content">
|
||||||
<div class="mainpage">
|
<div class="mainpage">
|
||||||
|
<div class="alert alert-warning alert-dismissible fade show block660" role="alert">
|
||||||
|
<span>alte Zugangsdaten ins neue System </span><a th:href="@{/migration/login}">umziehen</a>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Schließen"></button>
|
||||||
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var mytoggle = new MyToggle();
|
var mytoggle = new MyToggle();
|
||||||
</script>
|
</script>
|
||||||
<div class="card bottomdist16" style="max-width: 660px; margin-left: auto; margin-right: auto; background: transparent" th:each="c : ${camps}">
|
<div class="card bottomdist16 block660" style="background: transparent" th:each="c : ${camps}">
|
||||||
<div class="card-header mytoggle_btn" style="background: transparent" th:onclick="mytoggle.toggle('campdiv_[[${c.pk}]]')">
|
<div class="card-header mytoggle_btn" style="background: transparent" th:onclick="mytoggle.toggle('campdiv_[[${c.pk}]]')">
|
||||||
<div style="margin-left: auto; margin-right: auto;">
|
<div style="margin-left: auto; margin-right: auto;">
|
||||||
<span th:text="${c.name}" class="headlinefont"></span><span class="headlinefont"> </span><span th:text="${#numbers.formatInteger(c.year, 0)}" class="headlinefont"
|
<span th:text="${c.name}" class="headlinefont"></span><span class="headlinefont"> </span><span th:text="${#numbers.formatInteger(c.year, 0)}" class="headlinefont"
|
||||||
|
60
src/main/resources/templates/migration/login.html
Normal file
60
src/main/resources/templates/migration/login.html
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||||
|
<head>
|
||||||
|
<title>Camp Organizer 2</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<th:block layout:fragment="header">
|
||||||
|
Umziehen der Zugangsdaten aus dem alten Anmeldeportal
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="content">
|
||||||
|
<div class="mainpage">
|
||||||
|
<div class="alert alert-success alert-dismissible fade show block660" role="alert">
|
||||||
|
Mit dem Umzug in das neue Anmeldeportal ist es leider notwendig, dass du dir ein neues Login anlegst.
|
||||||
|
Damit das für dich leichter geht, haben wir ein Migrationswerkzeug entwickelt, mit dem du deinen alten Zugang übertragen kannst.<br />
|
||||||
|
<br />
|
||||||
|
Wichtig dabei ist, dass du beim Anlegen des neuen Zugangs eine gültige E-Mail-Adresse verwendest. Die wird im neuen System benötigt,
|
||||||
|
falls du dein Passwort vergessen hast. Damit eine sinnvolle Zuordnung möglich ist, gib bitte ebenfalls Vor- und Nachname an.<br />
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Schließen"></button>
|
||||||
|
</div>
|
||||||
|
<div class="block660">
|
||||||
|
<div class="card centered-card" style="max-width: 48rem">
|
||||||
|
<div class="card-body">
|
||||||
|
<form th:action="@{/migration/loginold}" th:object="${bean}" method="post">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 rowdist">
|
||||||
|
<span class="error" th:each="error : ${#fields.errors('username')}">[[${error}]]<br /></span>
|
||||||
|
<input type="text" placeholder="username" th:field="*{username}" th:class="${'form-control ' + (#fields.hasErrors('username') ? 'inputerror' : '')}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 rowdist">
|
||||||
|
<span class="error" th:each="error : ${#fields.errors('password')}">[[${error}]]<br /></span>
|
||||||
|
<input type="password" placeholder="Passwort" th:field="*{password}" th:class="${'form-control ' + (#fields.hasErrors('password') ? 'inputerror' : '')}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 rowdist">
|
||||||
|
<span class="error" th:each="error : ${#fields.errors('forename')}">[[${error}]]<br /></span>
|
||||||
|
<input type="text" placeholder="Vorname" th:field="*{forename}" th:class="${'form-control ' + (#fields.hasErrors('forename') ? 'inputerror' : '')}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 rowdist">
|
||||||
|
<span class="error" th:each="error : ${#fields.errors('surname')}">[[${error}]]<br /></span>
|
||||||
|
<input type="text" placeholder="Nachname" th:field="*{surname}" th:class="${'form-control ' + (#fields.hasErrors('surname') ? 'inputerror' : '')}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 rowdist">
|
||||||
|
<span class="error" th:each="error : ${#fields.errors('email')}">[[${error}]]<br /></span>
|
||||||
|
<input type="text" placeholder="E-Mail" th:field="*{email}" th:class="${'form-control ' + (#fields.hasErrors('email') ? 'inputerror' : '')}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 rowdist centered">
|
||||||
|
<input type="submit" class="btn btn-linda buttonfont" value="jetzt umziehen" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th:block>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -22,11 +22,11 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 rowdist">
|
<div class="col-sm-6 rowdist">
|
||||||
<span class="error" th:each="error : ${#fields.errors('surname')}">[[${error}]]<br /></span>
|
<span class="error" th:each="error : ${#fields.errors('forename')}">[[${error}]]<br /></span>
|
||||||
<input type="text" placeholder="Vorname" th:field="*{forename}" th:class="${'form-control ' + (#fields.hasErrors('forename') ? 'inputerror' : '')}" />
|
<input type="text" placeholder="Vorname" th:field="*{forename}" th:class="${'form-control ' + (#fields.hasErrors('forename') ? 'inputerror' : '')}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 rowdist">
|
<div class="col-sm-6 rowdist">
|
||||||
<span class="error" th:each="error : ${#fields.errors('forename')}">[[${error}]]<br /></span>
|
<span class="error" th:each="error : ${#fields.errors('surname')}">[[${error}]]<br /></span>
|
||||||
<input type="text" placeholder="Nachname" th:field="*{surname}" th:class="${'form-control ' + (#fields.hasErrors('surname') ? 'inputerror' : '')}" />
|
<input type="text" placeholder="Nachname" th:field="*{surname}" th:class="${'form-control ' + (#fields.hasErrors('surname') ? 'inputerror' : '')}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user