chore: reorganize into polyglot monorepo (workshop)
- Move bigmind/ -> mcp/bigmind/ - Move webscraper/ -> mcp/webscraper/ - Move mss-failsafe/ -> java/mss-failsafe/ - Move Wellmann-Shop/ -> java/wellmann-shop/ (normalize to kebab-case) - Add .roo/ IDE config files to tracking - Add plans/REPO_STRATEGY.md (monorepo strategy document) - Expand .gitignore: Java/Maven, Node/TS, coverage, uv.lock - Rewrite README.md as navigation index - Update .roo/mcp.json webscraper path to mcp/webscraper/
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package business.user;
|
||||
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Startup;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author patri
|
||||
*/
|
||||
@Named(value = "DemoManager")
|
||||
@ApplicationScoped
|
||||
@Startup
|
||||
public class DemoManager {
|
||||
|
||||
@EJB
|
||||
PersonManager personManager;
|
||||
|
||||
/**
|
||||
* Creates a new instance of NewJSFManagedBean
|
||||
*/
|
||||
public DemoManager() {
|
||||
runDemos();
|
||||
}
|
||||
|
||||
private void runDemos(){
|
||||
personManager.demo();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package business.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Named;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import model.person.Password;
|
||||
import model.person.Salt;
|
||||
import model.person.Person;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Named(value = "passwordManager")
|
||||
@Stateless
|
||||
public class PasswordManager implements Serializable {
|
||||
private static final long serialVersionUID = -4563304131856981259L;
|
||||
|
||||
final static Logger LOGGER = LogManager.getLogger(PasswordManager.class);
|
||||
|
||||
@PersistenceContext(name = "pu_person")
|
||||
private EntityManager em;
|
||||
|
||||
//private Password password;
|
||||
private Person user;
|
||||
|
||||
private final int keyLength = 256;
|
||||
|
||||
public byte[] hashPassword(final char[] password, final byte[] salt, final int iterations) {
|
||||
try {
|
||||
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
|
||||
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, this.keyLength);
|
||||
SecretKey key = skf.generateSecret(spec);
|
||||
//this.password = new Password(this.costumer, key.getEncoded());
|
||||
LOGGER.debug("Hash created!");
|
||||
return key.getEncoded();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
LOGGER.error("Failure creating hash for with:" + e);
|
||||
return null;
|
||||
//throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] hashPasswordUser(final char[] password, Person user) {
|
||||
|
||||
if (user == null) {
|
||||
LOGGER.error("Tried to create hash for Nullcostumer!");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
|
||||
PBEKeySpec spec = new PBEKeySpec(password, user.getSalt().getSalt(), user.getSalt().getInterations(), keyLength);
|
||||
SecretKey key = skf.generateSecret(spec);
|
||||
LOGGER.debug("Hash created!");
|
||||
return key.getEncoded();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
LOGGER.error("Failure creating hash for" + user.getEmail() + "with: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean passwordCheckEmail(final String email, final byte[] password) {
|
||||
TypedQuery<Person> query = em.createNamedQuery(Person.FIND_BY_EMAIL, Person.class);
|
||||
query.setParameter("email", email);
|
||||
try {
|
||||
Person user;
|
||||
user = query.getSingleResult();
|
||||
|
||||
boolean equals = Arrays.equals(password, user.getPassword().getPassword());
|
||||
|
||||
for (int i = 0; i < password.length; i++) {
|
||||
password[i] = 0;
|
||||
}
|
||||
|
||||
return equals;
|
||||
} catch (NoResultException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean passwordCheckCustomer(final Person user, final String password) {
|
||||
LOGGER.debug("Test " + user.getEmail() + " mit " + password);
|
||||
byte[] pw = hashPasswordUser(password.toCharArray(), user);
|
||||
|
||||
boolean equals = Arrays.equals(pw, user.getPassword().getPassword());
|
||||
|
||||
for (int i = 0; i < pw.length; i++) {
|
||||
pw[i] = 0;
|
||||
}
|
||||
|
||||
return equals;
|
||||
|
||||
}
|
||||
|
||||
public boolean changePassword(Person user, String newPassword, String oldPassword) {
|
||||
if (user == null) {
|
||||
LOGGER.error("Nullcostumer tried to change Password");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(passwordCheckCustomer(user, oldPassword)){
|
||||
user.getPassword().setPassowrd(hashPasswordUser(newPassword.toCharArray(), user));
|
||||
LOGGER.info("Password changed for " + user.getEmail());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
em.persist(user);
|
||||
LOGGER.info("Password changed for " + user.getEmail());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Couldn't save new password to " + user.getEmail() + " with: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] generateRandomPassword() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte bytes[] = new byte[20];
|
||||
random.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public Password gerateNewRandomPasswordClass(Person user){
|
||||
Salt salt = user.getSalt();
|
||||
String pass = Arrays.toString(generateRandomPassword());
|
||||
return new Password(user, hashPassword(pass.toCharArray(), salt.getSalt(), salt.getInterations()));
|
||||
}
|
||||
|
||||
public byte[] hashToken(String token){
|
||||
try {
|
||||
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
byte[] test = "SuperTestSalz".getBytes();
|
||||
PBEKeySpec spec = new PBEKeySpec(token.toCharArray(), test, 200, this.keyLength);
|
||||
SecretKey key = skf.generateSecret(spec);
|
||||
LOGGER.debug("TokenHash created!");
|
||||
return key.getEncoded();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
LOGGER.error("Failure creating tokenhash for " + token + " with: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Person getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(Person user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package business.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import controller.person.PersonController;
|
||||
import exception.InvalidEmailException;
|
||||
import exception.InvalidPasswordException;
|
||||
import exception.PersonInaktiveException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import model.person.Salt;
|
||||
import model.person.enums.TokenType;
|
||||
import model.person.Person;
|
||||
import model.person.enums.UserGroup;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Named
|
||||
@Stateless
|
||||
public class PersonManager implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6581582446436303658L;
|
||||
|
||||
final static Logger LOGGER = LogManager.getLogger(PersonManager.class);
|
||||
|
||||
@EJB
|
||||
private PasswordManager passwordManager;
|
||||
|
||||
@Inject
|
||||
private PersonController userController;
|
||||
|
||||
@PersistenceContext(name = "pu_person", type = PersistenceContextType.EXTENDED)
|
||||
private EntityManager em;
|
||||
|
||||
@Transactional
|
||||
public void demo() {
|
||||
Salt salt = new Salt();
|
||||
Salt salt2 = new Salt();
|
||||
Salt salt3 = new Salt();
|
||||
|
||||
Set<UserGroup> groupUser = new HashSet<>();
|
||||
groupUser.add(UserGroup.USER);
|
||||
|
||||
Set<UserGroup> adminUser = new HashSet<>();
|
||||
adminUser.add(UserGroup.ADMIN);
|
||||
|
||||
Person test = new Person(
|
||||
"user@test.de",
|
||||
(passwordManager.hashPassword("test".toCharArray(), salt.getSalt(), salt.getInterations())),
|
||||
salt,
|
||||
groupUser
|
||||
);
|
||||
|
||||
test.setFirstname("User");
|
||||
test.setLastname("Nachname");
|
||||
test.setMobile("0124584589");
|
||||
test.setFax("3445565675");
|
||||
test.setTelefon("042154585");
|
||||
test.setActive(true);
|
||||
em.persist(test);
|
||||
|
||||
Person testAdmin = new Person(
|
||||
"admin@test.de",
|
||||
(passwordManager.hashPassword("admin".toCharArray(), salt2.getSalt(), salt2.getInterations())),
|
||||
salt2,
|
||||
adminUser
|
||||
);
|
||||
|
||||
testAdmin.setFirstname("Admin");
|
||||
testAdmin.setLastname("Administratori");
|
||||
testAdmin.setMobile("0124584589");
|
||||
testAdmin.setFax("3445565675");
|
||||
testAdmin.setTelefon("042154585");
|
||||
testAdmin.setActive(true);
|
||||
em.persist(testAdmin);
|
||||
|
||||
Person testInactive = new Person(
|
||||
"inaktive@test.de",
|
||||
(passwordManager.hashPassword("test".toCharArray(), salt3.getSalt(), salt3.getInterations())),
|
||||
salt3,
|
||||
groupUser
|
||||
);
|
||||
|
||||
testInactive.setFirstname("Admin");
|
||||
testInactive.setLastname("Administratori");
|
||||
testInactive.setMobile("0124584589");
|
||||
testInactive.setFax("3445565675");
|
||||
testInactive.setTelefon("042154585");
|
||||
testInactive.setActive(false);
|
||||
em.persist(testInactive);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Person load(Person user) {
|
||||
try {
|
||||
Person loaded = this.em.find(Person.class, user.getId());
|
||||
LOGGER.info(loaded);
|
||||
|
||||
return loaded;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Person getActiveUser() {
|
||||
try {
|
||||
Person user = em.find(Person.class, userController.getActiveUser().getId());
|
||||
return user;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("couldn't load user: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Person getPlainActiveUser() {
|
||||
try {
|
||||
Person user = em.find(Person.class, userController.getActiveUser().getId());
|
||||
return user;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("couldn't load user: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Person> getByEmail(String email) {
|
||||
try {
|
||||
Person person = this.em.createNamedQuery(Person.FIND_BY_EMAIL, Person.class)
|
||||
.setParameter("email", email).getSingleResult();
|
||||
|
||||
if (person != null) {
|
||||
person.getUserGroups().size();
|
||||
}
|
||||
|
||||
return Optional.of(person);
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Person> getByLoginToken(String loginToken, TokenType tokenType) {
|
||||
Optional<Person> optional;
|
||||
try {
|
||||
|
||||
optional = Optional.of(this.em.createNamedQuery(Person.FIND_BY_TOKEN, Person.class)
|
||||
.setParameter("tokenHash", this.passwordManager.hashToken(loginToken))
|
||||
.setParameter("tokenType", tokenType)
|
||||
.setParameter("timestamp", Instant.now())
|
||||
.getSingleResult()
|
||||
);
|
||||
return optional;
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public Person getByEmailAndPassword(String email, String password) {
|
||||
Person managedUser = getByEmail(email).orElseThrow(InvalidEmailException::new);
|
||||
LOGGER.debug("Loaded " + managedUser.getEmail());
|
||||
if (!passwordManager.passwordCheckCustomer(managedUser, password)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
if (!managedUser.isActive()) {
|
||||
throw new PersonInaktiveException();
|
||||
}
|
||||
userController.setActiveUser(managedUser);
|
||||
return managedUser;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean save(Person user) {
|
||||
if (user == null) {
|
||||
LOGGER.error("Tried to save null or Nullcustomer");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (user.getId() != null && user.getId() > 0) {
|
||||
em.merge(user);
|
||||
} else {
|
||||
em.persist(user);
|
||||
}
|
||||
LOGGER.info("Saved " + user.getEmail());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Tried to save " + user.getEmail() + " with error: " + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(Person user) {
|
||||
if (user == null) {
|
||||
LOGGER.error("Tried to save null or Nullcustomer");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
em.refresh(user);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Tried to refresh " + user.getEmail() + " with error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public String resetPassword() {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package business.user;
|
||||
|
||||
import java.time.Instant;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
import static java.util.UUID.randomUUID;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import exception.InvalidEmailException;
|
||||
import model.person.Token;
|
||||
import model.person.enums.TokenType;
|
||||
import model.person.Person;
|
||||
|
||||
import java.util.Arrays;
|
||||
import static java.time.Instant.now;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Stateless
|
||||
public class TokenManager {
|
||||
|
||||
@PersistenceContext(name = "pu_person")
|
||||
private EntityManager em;
|
||||
|
||||
@Inject
|
||||
PasswordManager passwordManager;
|
||||
|
||||
@Inject
|
||||
PersonManager customerManager;
|
||||
|
||||
public String generate(final String email, final String ipAddress, final String description,
|
||||
final TokenType tokenType) {
|
||||
|
||||
String rawToken = randomUUID().toString();
|
||||
Instant expiration = now().plus(14, DAYS);
|
||||
|
||||
save(rawToken, email, ipAddress, description, tokenType, expiration);
|
||||
|
||||
return rawToken;
|
||||
}
|
||||
|
||||
public String generateFileToken(final String email, final String description) {
|
||||
|
||||
String rawToken = randomUUID().toString();
|
||||
Instant expiration = now().plus(3, DAYS);
|
||||
|
||||
save(rawToken, email, null, description, TokenType.FILE, expiration);
|
||||
|
||||
return rawToken;
|
||||
}
|
||||
|
||||
public void save(final String rawToken, final String email, final String ipAddress,
|
||||
final String description, final TokenType tokenType, final Instant expiration) {
|
||||
|
||||
Person user = this.customerManager.getByEmail(email)
|
||||
.orElseThrow(InvalidEmailException::new);
|
||||
|
||||
Token token = new Token();
|
||||
|
||||
token.setTokenHash(Arrays.toString(this.passwordManager.hashToken(rawToken)));
|
||||
token.setExpiration(expiration);
|
||||
token.setDescription(description);
|
||||
token.setTokenType(tokenType);
|
||||
token.setIpAddress(ipAddress);
|
||||
|
||||
user.addToken(token);
|
||||
|
||||
this.em.persist(user);
|
||||
}
|
||||
|
||||
public void remove(String token) {
|
||||
this.em.createNamedQuery(Token.REMOVE_TOKEN)
|
||||
.setParameter("tokenHash", token).executeUpdate();
|
||||
}
|
||||
|
||||
public void removeExpired() {
|
||||
|
||||
this.em.createNamedQuery(Token.REMOVE_EXPIRED_TOKEN)
|
||||
.setParameter("timestamp", Instant.now())
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package controller;
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.faces.application.FacesMessage;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
public abstract class AbstractController implements Serializable{
|
||||
private static final long serialVersionUID = -5908716187853409719L;
|
||||
|
||||
protected void sendInfoMessage(String title, String message){
|
||||
FacesMessage facesMessage = new FacesMessage(
|
||||
FacesMessage.SEVERITY_INFO, title, message);
|
||||
addMessage(facesMessage);
|
||||
}
|
||||
|
||||
protected void sendWarnMessage(String title, String message){
|
||||
FacesMessage facesMessage = new FacesMessage(
|
||||
FacesMessage.SEVERITY_WARN, title, message);
|
||||
addMessage(facesMessage);
|
||||
}
|
||||
|
||||
protected void sendErrorMessage(String title, String message){
|
||||
FacesMessage facesMessage = new FacesMessage(
|
||||
FacesMessage.SEVERITY_ERROR, title, message);
|
||||
addMessage(facesMessage);
|
||||
}
|
||||
|
||||
protected void sendFatalMessage(String title, String message){
|
||||
FacesMessage facesMessage = new FacesMessage(
|
||||
FacesMessage.SEVERITY_FATAL, title, message);
|
||||
addMessage(facesMessage);
|
||||
}
|
||||
|
||||
private void addMessage(FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
protected void errorMessage() {
|
||||
String title = "Fehler!";
|
||||
String info = "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut!";
|
||||
sendErrorMessage(title, info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package controller.person;
|
||||
|
||||
import javax.enterprise.context.SessionScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.security.enterprise.AuthenticationStatus;
|
||||
import javax.security.enterprise.SecurityContext;
|
||||
import javax.security.enterprise.credential.Password;
|
||||
import javax.security.enterprise.credential.UsernamePasswordCredential;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import controller.AbstractController;
|
||||
import exception.InvalidEmailException;
|
||||
import exception.InvalidPasswordException;
|
||||
import exception.PersonInaktiveException;
|
||||
import httpauthenticationmechanism.ManagedPerson;
|
||||
import model.person.Person;
|
||||
|
||||
import static javax.security.enterprise.AuthenticationStatus.SEND_FAILURE;
|
||||
import static javax.security.enterprise.AuthenticationStatus.SUCCESS;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import static javax.security.enterprise.authentication.mechanism.http.AuthenticationParameters.withParams;
|
||||
import model.person.enums.UserGroup;
|
||||
import org.omnifaces.cdi.Param;
|
||||
import static org.omnifaces.util.Faces.getRequest;
|
||||
import static org.omnifaces.util.Faces.getResponse;
|
||||
import static org.omnifaces.util.Faces.redirect;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Named
|
||||
@SessionScoped
|
||||
public class PersonController extends AbstractController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2257766986862616262L;
|
||||
final static Logger LOGGER = LogManager.getLogger(PersonController.class);
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean rememberMe = false;
|
||||
|
||||
@Inject
|
||||
SecurityContext securityContext;
|
||||
|
||||
@Inject
|
||||
ManagedPerson managedPerson;
|
||||
|
||||
@Param(name = "continue") // Defined in @LoginToContinue of SecurityFormAuthenticationMechanism
|
||||
private boolean loginToContinue;
|
||||
|
||||
private Person activePerson;
|
||||
|
||||
public PersonController() {
|
||||
|
||||
}
|
||||
|
||||
public String submit() {
|
||||
|
||||
try {
|
||||
// credential that want to be validate was UsernamePasswordCredential
|
||||
UsernamePasswordCredential credential = new UsernamePasswordCredential(username, new Password(password));
|
||||
|
||||
// this will call our security configuration to authorize the user
|
||||
AuthenticationStatus status = securityContext.authenticate(
|
||||
getRequest(),
|
||||
getResponse(),
|
||||
withParams()
|
||||
.credential(credential)
|
||||
.newAuthentication(!loginToContinue)
|
||||
.rememberMe(rememberMe)
|
||||
);
|
||||
|
||||
// When logged in choose the right page by class. When more then one group
|
||||
// fits then the higher order is used
|
||||
if (status.equals(SUCCESS)) {
|
||||
managedPerson.addLogin(username);
|
||||
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
|
||||
session.setAttribute("user", this);
|
||||
session.setAttribute("realUsername", username);
|
||||
|
||||
if (securityContext.isCallerInRole(UserGroup.ADMIN.toString())) {
|
||||
LOGGER.info("Login succesfull " + username + " with role: ADMIN");
|
||||
return "admin/welcome.xhtml?faces-redirect=true";
|
||||
}
|
||||
|
||||
if (securityContext.isCallerInRole(UserGroup.USER.toString())) {
|
||||
LOGGER.info("Login succesfull " + username + " with role: USER");
|
||||
return "user/welcome.xhtml?faces-redirect=true";
|
||||
}
|
||||
|
||||
if (securityContext.isCallerInRole(UserGroup.CUSTOMER.toString())) {
|
||||
LOGGER.info("Login succesfull " + username + " with role: USER");
|
||||
return "customer/welcome.xhtml?faces-redirect=true";
|
||||
}
|
||||
|
||||
redirect("index.xhtml");
|
||||
|
||||
} else if (status.equals(SEND_FAILURE)) {
|
||||
|
||||
sendErrorMessage("Fehler!", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut!.");
|
||||
return "";
|
||||
}
|
||||
} catch (InvalidPasswordException | InvalidEmailException e) {
|
||||
LOGGER.info("Wrong Email or Password: " + username);
|
||||
sendErrorMessage("Fehler!", "Falsche Email oder Passwort!");
|
||||
return "";
|
||||
} catch (PersonInaktiveException p){
|
||||
sendErrorMessage("Fehler!", " Ihr Konto ist inatkiv. Bitte wenden Sie sich an den Administator.");
|
||||
return "";
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Login error with " + e);
|
||||
sendErrorMessage("Fehler!", "Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut!");
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String logout() {
|
||||
LOGGER.info("User is logging out: " + username);
|
||||
try {
|
||||
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("couldn't logout " + username + "with:" + e);
|
||||
}
|
||||
|
||||
return "index.xhtml?faces-redirect=true";
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public Person getActiveUser() {
|
||||
return activePerson;
|
||||
}
|
||||
|
||||
public void setActiveUser(Person activeUser) {
|
||||
this.activePerson = activeUser;
|
||||
}
|
||||
|
||||
public Set<String> getLogins() {
|
||||
return managedPerson.getLogins();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package exception;
|
||||
|
||||
import javax.ejb.ApplicationException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@ApplicationException(rollback = true)
|
||||
public abstract class AbstractBusinessException extends RuntimeException {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package exception;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
public class InvalidCredentialException extends AbstractBusinessException{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package exception;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
public class InvalidEmailException extends AbstractBusinessException {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package exception;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
public class InvalidPasswordException extends AbstractBusinessException {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package exception;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author patri
|
||||
*/
|
||||
public class PersonInaktiveException extends AbstractBusinessException{
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package httpauthenticationmechanism;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.security.enterprise.credential.CallerOnlyCredential;
|
||||
import javax.security.enterprise.credential.Credential;
|
||||
import javax.security.enterprise.credential.UsernamePasswordCredential;
|
||||
import javax.security.enterprise.identitystore.CredentialValidationResult;
|
||||
import static javax.security.enterprise.identitystore.CredentialValidationResult.INVALID_RESULT;
|
||||
import static javax.security.enterprise.identitystore.CredentialValidationResult.NOT_VALIDATED_RESULT;
|
||||
import javax.security.enterprise.identitystore.IdentityStore;
|
||||
|
||||
import business.user.PersonManager;
|
||||
import exception.InvalidCredentialException;
|
||||
import exception.PersonInaktiveException;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.ejb.EJB;
|
||||
import model.person.Person;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class AppIdentityStore implements IdentityStore {
|
||||
|
||||
@EJB
|
||||
PersonManager userManager;
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 90;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CredentialValidationResult validate(Credential credential) {
|
||||
try {
|
||||
|
||||
// check if the credential was UsernamePasswordCredential
|
||||
if (credential instanceof UsernamePasswordCredential) {
|
||||
String username = ((UsernamePasswordCredential) credential).getCaller();
|
||||
String password = ((UsernamePasswordCredential) credential).getPasswordAsString();
|
||||
|
||||
return validate(this.userManager.getByEmailAndPassword(username, password));
|
||||
}
|
||||
|
||||
// check if the credential was CallerOnlyCredential
|
||||
if (credential instanceof CallerOnlyCredential) {
|
||||
String username = ((CallerOnlyCredential) credential).getCaller();
|
||||
|
||||
return validate(
|
||||
this.userManager.getByEmail(username)
|
||||
.orElseThrow(InvalidCredentialException::new)
|
||||
);
|
||||
}
|
||||
|
||||
} catch (InvalidCredentialException e) {
|
||||
return INVALID_RESULT;
|
||||
}
|
||||
return NOT_VALIDATED_RESULT;
|
||||
}
|
||||
|
||||
private CredentialValidationResult validate(Person person) {
|
||||
Set<String> groups;
|
||||
|
||||
groups = person.getUserGroups().stream()
|
||||
.map(gr -> gr.toString())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return new CredentialValidationResult(person.getEmail(), groups);
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package httpauthenticationmechanism;
|
||||
|
||||
import static javax.security.enterprise.identitystore.CredentialValidationResult.INVALID_RESULT;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.ejb.EJB;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.security.enterprise.CallerPrincipal;
|
||||
import javax.security.enterprise.credential.RememberMeCredential;
|
||||
import javax.security.enterprise.identitystore.CredentialValidationResult;
|
||||
import javax.security.enterprise.identitystore.RememberMeIdentityStore;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import business.user.TokenManager;
|
||||
import business.user.PersonManager;
|
||||
import model.person.Person;
|
||||
import static model.person.enums.TokenType.REMEMBER_ME;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class AppRememberMeIdentityStore implements RememberMeIdentityStore {
|
||||
@Inject
|
||||
HttpServletRequest request;
|
||||
|
||||
@EJB
|
||||
PersonManager userManager;
|
||||
|
||||
@EJB
|
||||
TokenManager tokenManager;
|
||||
|
||||
@Override
|
||||
public CredentialValidationResult validate(RememberMeCredential rmc) {
|
||||
Optional<Person> user = this.userManager.getByLoginToken(rmc.getToken(), REMEMBER_ME);
|
||||
|
||||
if (user.isPresent()) {
|
||||
return new CredentialValidationResult(user.get().getEmail());
|
||||
} else {
|
||||
return INVALID_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateLoginToken(CallerPrincipal cp, Set<String> set) {
|
||||
return this.tokenManager.generate(cp.getName(), getRemoteAddr(request), getDescription(), REMEMBER_ME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLoginToken(String string) {
|
||||
this.tokenManager.remove(string);
|
||||
}
|
||||
|
||||
private String getRemoteAddr(HttpServletRequest request){
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
private String getDescription() {
|
||||
return "Remember me session: " + this.request.getHeader("User-Agent");
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package httpauthenticationmechanism;
|
||||
|
||||
import business.user.PersonManager;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.ejb.EJB;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.security.enterprise.AuthenticationStatus;
|
||||
import javax.security.enterprise.authentication.mechanism.http.AutoApplySession;
|
||||
import javax.security.enterprise.authentication.mechanism.http.CustomFormAuthenticationMechanismDefinition;
|
||||
import javax.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism;
|
||||
import javax.security.enterprise.authentication.mechanism.http.HttpMessageContext;
|
||||
import javax.security.enterprise.authentication.mechanism.http.LoginToContinue;
|
||||
import javax.security.enterprise.authentication.mechanism.http.RememberMe;
|
||||
import javax.security.enterprise.credential.Credential;
|
||||
import javax.security.enterprise.identitystore.IdentityStore;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@AutoApplySession // For "Is user already logged-in?"
|
||||
@RememberMe(
|
||||
cookieMaxAgeSeconds = 60 * 60 * 24 * 14, // 14 days
|
||||
cookieSecureOnly = false, // Remove this when login is served over HTTPS.
|
||||
isRememberMeExpression = "#{self.isRememberMe(httpMessageContext)}"
|
||||
)
|
||||
@LoginToContinue(
|
||||
loginPage = "/index.xhtml",
|
||||
errorPage = "/error.xhtml",
|
||||
useForwardToLogin = true
|
||||
)
|
||||
@ApplicationScoped
|
||||
public class ApplicationConfig implements HttpAuthenticationMechanism{
|
||||
|
||||
final static Logger LOGGER = LogManager.getLogger(ApplicationConfig.class);
|
||||
|
||||
public ApplicationConfig() {
|
||||
}
|
||||
|
||||
@Inject
|
||||
private IdentityStore identityStore;
|
||||
|
||||
@Inject
|
||||
private ManagedPerson managedPerson;
|
||||
|
||||
@EJB
|
||||
private PersonManager personManager;
|
||||
|
||||
@PostConstruct
|
||||
private void init(){
|
||||
managedPerson.getLogins();
|
||||
personManager.demo();
|
||||
|
||||
System.out.println("PostConstruct DEMO");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationStatus validateRequest(HttpServletRequest req, HttpServletResponse res, HttpMessageContext context) {
|
||||
|
||||
Credential credential = context.getAuthParameters().getCredential();
|
||||
|
||||
if (credential != null) {
|
||||
return context.notifyContainerAboutLogin(this.identityStore.validate(credential));
|
||||
} else {
|
||||
return context.doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
// this was called on @RememberMe annotations
|
||||
public Boolean isRememberMe(HttpMessageContext httpMessageContext) {
|
||||
return httpMessageContext.getAuthParameters().isRememberMe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanSubject(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) {
|
||||
HttpAuthenticationMechanism.super.cleanSubject(request, response, httpMessageContext);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package httpauthenticationmechanism;
|
||||
|
||||
import javax.servlet.annotation.WebListener;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import controller.person.PersonController;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@WebListener
|
||||
public class LogoutListener implements HttpSessionListener{
|
||||
final static Logger LOGGER = LogManager.getLogger(LogoutListener.class);
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent event) {
|
||||
// NOOP.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent event) {
|
||||
LOGGER.info("Session destroyed");
|
||||
PersonController userManager = (PersonController) event.getSession().getAttribute("user");
|
||||
String username = (String) event.getSession().getAttribute("realUsername");
|
||||
if (userManager != null && username != null) {
|
||||
LOGGER.info("not nulls");
|
||||
userManager.getLogins().remove(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package httpauthenticationmechanism;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.inject.Named;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Named(value = "managedPerson")
|
||||
@ApplicationScoped
|
||||
public class ManagedPerson {
|
||||
|
||||
private Set<String> logins;
|
||||
|
||||
/**
|
||||
* Creates a new instance of ManagedCustomer
|
||||
*/
|
||||
public ManagedPerson() {
|
||||
}
|
||||
|
||||
public Set<String> getLogins(){
|
||||
if (this.logins == null) {
|
||||
this.logins = new HashSet<>();
|
||||
}
|
||||
|
||||
return this.logins;
|
||||
}
|
||||
|
||||
public void addLogin(String user){
|
||||
getLogins().add(user);
|
||||
}
|
||||
|
||||
public void removeLogin(String user){
|
||||
getLogins().remove(user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package model;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick Plate
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public class AbstractEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private LocalDateTime changedDate;
|
||||
|
||||
private LocalDateTime creationDate;
|
||||
|
||||
private boolean outdated;
|
||||
|
||||
public AbstractEntity() {
|
||||
this.creationDate = LocalDateTime.now();
|
||||
this.changedDate = this.creationDate;
|
||||
this.outdated = false;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (object == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(object.getClass() == this.getClass())) {
|
||||
return false;
|
||||
}
|
||||
AbstractEntity other = (AbstractEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isOutdated() {
|
||||
return outdated;
|
||||
}
|
||||
|
||||
public void setOutdated(boolean outdated) {
|
||||
this.outdated = outdated;
|
||||
}
|
||||
|
||||
public LocalDateTime getChangedDate() {
|
||||
return changedDate;
|
||||
}
|
||||
|
||||
public void setChangedDate(LocalDateTime changedDate) {
|
||||
this.changedDate = changedDate;
|
||||
}
|
||||
|
||||
public void setCreationDate (LocalDateTime creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package model.person;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import model.AbstractEntity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "Password.findByPassword",
|
||||
query = "SELECT p FROM Password p WHERE p.password = :password"),
|
||||
@NamedQuery(name = "Password.findByCostumerID",
|
||||
query = "SELECT p FROM Password p WHERE p.person = :person")
|
||||
})
|
||||
public class Password extends AbstractEntity {
|
||||
private static final long serialVersionUID = -1924150926160449302L;
|
||||
|
||||
@OneToOne
|
||||
private Person person;
|
||||
|
||||
@Column(name="password")
|
||||
private byte[] password;
|
||||
|
||||
public Password() {
|
||||
}
|
||||
|
||||
public Password (Person person, byte[] password) {
|
||||
this.person = person;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public byte[] getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassowrd(byte[] password){
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 79 * hash + Objects.hashCode(this.person);
|
||||
hash = 79 * hash + Arrays.hashCode(this.password);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Password other = (Password) obj;
|
||||
if (!Objects.equals(this.person, other.person)) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(this.password, other.password)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package model.person;
|
||||
|
||||
import model.person.enums.Call;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
import model.AbstractEntity;
|
||||
import model.person.enums.UserGroup;
|
||||
|
||||
/**
|
||||
* Entity implementation class for Entity: User
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = Person.FIND_BY_EMAIL,
|
||||
query = "SELECT p FROM Person p WHERE p.email = :email"),
|
||||
@NamedQuery(name = Person.FIND_BY_ID,
|
||||
query = "SELECT p FROM Person p WHERE p.id = :id"),
|
||||
@NamedQuery(name = Person.FIND_BY_TOKEN,
|
||||
query = "SELECT p FROM Person p inner join p.tokens t where t.tokenHash = :tokenHash and t.tokenType = :tokenType and t.expiration > :timestamp")
|
||||
})
|
||||
public class Person extends AbstractEntity implements Serializable {
|
||||
|
||||
public static final String FIND_BY_EMAIL = "Person.findByEmail";
|
||||
public static final String FIND_BY_ID = "Person.findByID";
|
||||
public static final String FIND_BY_TOKEN = "Person.findByToken";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "Email", unique = true, nullable = false)
|
||||
private String email;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "Password_ID", nullable = false, unique = true)
|
||||
private Password password;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "Salt_ID", nullable = false, unique = true)
|
||||
private Salt salt;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "Anrede")
|
||||
private Call call;
|
||||
|
||||
@OneToMany(mappedBy = "person", orphanRemoval = true, cascade = CascadeType.ALL)
|
||||
private List<Token> tokens;
|
||||
|
||||
@ElementCollection(targetClass = UserGroup.class)
|
||||
@Enumerated(EnumType.STRING)
|
||||
@JoinTable(name = "UserGroups", joinColumns = @JoinColumn(name = "UserID"))
|
||||
@Column(name = "UserGroups", nullable = false)
|
||||
private Set<UserGroup> userGroups;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String telefon;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String mobile;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String fax;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String firstname;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String lastname;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String title;
|
||||
|
||||
@Column(nullable = true)
|
||||
private boolean active;
|
||||
|
||||
public Person() {
|
||||
super();
|
||||
active = false;
|
||||
}
|
||||
|
||||
public Person(String email, byte[] password, Salt salt, Set<UserGroup> usergroups) {
|
||||
this.email = email;
|
||||
this.tokens = new ArrayList<>();
|
||||
this.salt = salt;
|
||||
this.password = new Password(this, password);
|
||||
this.userGroups = usergroups;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Password getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(Password password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Salt getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(Salt salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public Call getCall() {
|
||||
return call;
|
||||
}
|
||||
|
||||
public void setCall(Call call) {
|
||||
this.call = call;
|
||||
}
|
||||
|
||||
public String getTelefon() {
|
||||
return telefon;
|
||||
}
|
||||
|
||||
public void setTelefon(String telefon) {
|
||||
this.telefon = telefon;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getFax() {
|
||||
return fax;
|
||||
}
|
||||
|
||||
public void setFax(String fax) {
|
||||
this.fax = fax;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public List<Token> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public void setTokens(List<Token> tokens) {
|
||||
this.tokens = tokens;
|
||||
}
|
||||
|
||||
public void addToken(Token token) {
|
||||
if (this.tokens == null) {
|
||||
tokens = new ArrayList<>();
|
||||
}
|
||||
|
||||
tokens.add(token);
|
||||
}
|
||||
|
||||
public Set<UserGroup> getUserGroups() {
|
||||
return userGroups;
|
||||
}
|
||||
|
||||
public void setUserGroups(Set<UserGroup> userGroups) {
|
||||
this.userGroups = userGroups;
|
||||
}
|
||||
|
||||
public void addGroup(UserGroup userGroup){
|
||||
if (this.userGroups == null) {
|
||||
this.userGroups = new HashSet<>();
|
||||
}
|
||||
|
||||
this.userGroups.add(userGroup);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package model.person;
|
||||
|
||||
//import java.nio.charset.Charset;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import model.AbstractEntity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Entity
|
||||
public class Salt extends AbstractEntity {
|
||||
|
||||
//private final Charset UTF8_CHARSET = Charset.forName("UTF-8");
|
||||
private static final long serialVersionUID = -1068077226987746862L;
|
||||
private byte[] salt;
|
||||
private int interations;
|
||||
|
||||
public Salt() {
|
||||
interations = 3072;
|
||||
generateSalt();
|
||||
}
|
||||
|
||||
private void generateSalt() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte bytes[] = new byte[64];
|
||||
random.nextBytes(bytes);
|
||||
salt = bytes;
|
||||
}
|
||||
|
||||
public java.lang.String bytetoString(byte[] input) {
|
||||
return Arrays.toString(input);
|
||||
}
|
||||
|
||||
public byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public int getInterations() {
|
||||
return interations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 79 * hash + Arrays.hashCode(this.salt);
|
||||
hash = 79 * hash + this.interations;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Salt other = (Salt) obj;
|
||||
if (this.interations != other.interations) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(this.salt, other.salt)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package model.person;
|
||||
|
||||
import model.person.enums.TokenType;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import model.AbstractEntity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "token", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"token_hash"})
|
||||
})
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = Token.REMOVE_TOKEN, query = "DELETE FROM Token t where t.tokenHash = :tokenHash"),
|
||||
@NamedQuery(name = Token.REMOVE_EXPIRED_TOKEN, query = "DELETE FROM Token t where t.expiration < :timestamp")
|
||||
})
|
||||
public class Token extends AbstractEntity {
|
||||
|
||||
private static final long serialVersionUID = -6632692800064453512L;
|
||||
public static final String REMOVE_TOKEN = "Token.removeToken";
|
||||
public static final String REMOVE_EXPIRED_TOKEN = "Token.removeExpiredToken";
|
||||
|
||||
@Column(name = "token_hash")
|
||||
private String tokenHash;
|
||||
|
||||
@Column(name = "token_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TokenType tokenType;
|
||||
|
||||
@Column(name = "ip_address", length = 45)
|
||||
private String ipAddress;
|
||||
|
||||
private String description;
|
||||
|
||||
private Instant created;
|
||||
|
||||
private Instant expiration;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "account_id")
|
||||
private Person person;
|
||||
|
||||
public Token() {
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
public void generateInformation() {
|
||||
this.created = Instant.now();
|
||||
if (this.expiration == null) {
|
||||
this.expiration = this.created.plus(1, MONTHS);
|
||||
}
|
||||
}
|
||||
|
||||
public String getTokenHash() {
|
||||
return tokenHash;
|
||||
}
|
||||
|
||||
public void setTokenHash(String tokenHash) {
|
||||
this.tokenHash = tokenHash;
|
||||
}
|
||||
|
||||
public TokenType getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
public void setTokenType(TokenType tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Instant getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Instant created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Instant getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Instant expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
/* don't depend on natural identifier for equality checks, see: https://vladmihalcea.com/2017/03/29/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/#more-7143 */
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Token token = (Token) obj;
|
||||
return Objects.equals(getId(), token.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Token{ id " + getId() + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package model.person.enums;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public enum Call {
|
||||
HERR(0), FRAU(1), DIVERS(2), UNBESTIMMT(3);
|
||||
|
||||
private final int type;
|
||||
private Locale locale = null;
|
||||
|
||||
private Call(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (locale == null || Locale.GERMAN.equals(locale)) {
|
||||
switch (this) {
|
||||
case HERR:
|
||||
return "Herr";
|
||||
case FRAU:
|
||||
return "Frau";
|
||||
case DIVERS:
|
||||
return "Divers";
|
||||
case UNBESTIMMT:
|
||||
return "Unbestimmt";
|
||||
}
|
||||
}
|
||||
|
||||
if (locale.equals(Locale.ENGLISH)) {
|
||||
switch (this) {
|
||||
case HERR:
|
||||
return "Mr";
|
||||
case FRAU:
|
||||
return "Mrs";
|
||||
case DIVERS:
|
||||
return "divers";
|
||||
case UNBESTIMMT:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package model.person.enums;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrick
|
||||
*/
|
||||
public enum TokenType {
|
||||
REMEMBER_ME,
|
||||
API,
|
||||
RESET_PASSWORD,
|
||||
FILE
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package model.person.enums;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author patri
|
||||
*/
|
||||
public enum UserGroup {
|
||||
USER,
|
||||
ADMIN,
|
||||
CUSTOMER;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
|
||||
<!-- Define Persistence Unit -->
|
||||
<persistence-unit name="pu_person">
|
||||
<jta-data-source>java:/mss-failsave</jta-data-source>
|
||||
<class>model.person.Token</class>
|
||||
<class>model.person.Salt</class>
|
||||
<class>model.person.Person</class>
|
||||
<class>model.person.Password</class>
|
||||
<properties>
|
||||
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
Reference in New Issue
Block a user