[Major] Implemented soft migration to salt based privilege persistence

This commit is contained in:
Robert von Burg 2018-02-08 12:51:01 +01:00
parent b07d2322ac
commit 17aeff6672
12 changed files with 440 additions and 219 deletions

View File

@ -2,6 +2,7 @@ package li.strolch.privilege.base;
public class PrivilegeConstants { public class PrivilegeConstants {
public static final String DEFAULT_ALGORITHM_NON_SALT = "SHA-256";
public static final String DEFAULT_ALGORITHM = "PBKDF2WithHmacSHA512"; public static final String DEFAULT_ALGORITHM = "PBKDF2WithHmacSHA512";
public static final int DEFAULT_KEY_LENGTH = 256; public static final int DEFAULT_KEY_LENGTH = 256;
public static final int DEFAULT_SMALL_ITERATIONS = 10000; public static final int DEFAULT_SMALL_ITERATIONS = 10000;

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,9 +15,7 @@
*/ */
package li.strolch.privilege.handler; package li.strolch.privilege.handler;
import static li.strolch.privilege.base.PrivilegeConstants.DEFAULT_ALGORITHM; import static li.strolch.privilege.base.PrivilegeConstants.*;
import static li.strolch.privilege.base.PrivilegeConstants.DEFAULT_ITERATIONS;
import static li.strolch.privilege.base.PrivilegeConstants.DEFAULT_KEY_LENGTH;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKeyFactory;
@ -61,6 +59,11 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
*/ */
private SecureRandom secureRandom; private SecureRandom secureRandom;
/**
* The non-salt algorithm for this instance
*/
private String nonSaltAlgorithm;
/** /**
* The configured algorithm for this instance * The configured algorithm for this instance
*/ */
@ -110,12 +113,30 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
return bytes; return bytes;
} }
@Override
public byte[] hashPasswordWithoutSalt(char[] password) {
try {
MessageDigest digest = MessageDigest.getInstance(this.nonSaltAlgorithm);
return digest.digest(new String(password).getBytes());
} catch (NoSuchAlgorithmException e) {
throw new PrivilegeException(MessageFormat.format("Algorithm {0} was not found!", nonSaltAlgorithm),
e.getCause());
}
}
@Override @Override
public byte[] hashPassword(char[] password, byte[] salt) { public byte[] hashPassword(char[] password, byte[] salt) {
return hashPassword(password, salt, this.algorithm, this.iterations, this.keyLength);
}
@Override
public byte[] hashPassword(char[] password, byte[] salt, String algorithm, int iterations, int keyLength) {
try { try {
SecretKeyFactory skf = SecretKeyFactory.getInstance(this.algorithm); SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
PBEKeySpec spec = new PBEKeySpec(password, salt, this.iterations, this.keyLength); PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);
SecretKey key = skf.generateSecret(spec); SecretKey key = skf.generateSecret(spec);
return key.getEncoded(); return key.getEncoded();
@ -131,11 +152,26 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
// get hash algorithm parameters // get hash algorithm parameters
this.algorithm = parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM); this.algorithm = parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
this.nonSaltAlgorithm = parameterMap
.getOrDefault(XmlConstants.XML_PARAM_HASH_ALGORITHM_NON_SALT, DEFAULT_ALGORITHM_NON_SALT);
this.iterations = Integer.parseInt( this.iterations = Integer.parseInt(
parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_ITERATIONS, String.valueOf(DEFAULT_ITERATIONS))); parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_ITERATIONS, String.valueOf(DEFAULT_ITERATIONS)));
this.keyLength = Integer.parseInt( this.keyLength = Integer.parseInt(
parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_KEY_LENGTH, String.valueOf(DEFAULT_KEY_LENGTH))); parameterMap.getOrDefault(XmlConstants.XML_PARAM_HASH_KEY_LENGTH, String.valueOf(DEFAULT_KEY_LENGTH)));
// test non-salt hash algorithm
try {
hashPasswordWithoutSalt("test".toCharArray()); //$NON-NLS-1$
DefaultEncryptionHandler.logger.info(MessageFormat
.format("Using non-salt hashing algorithm {0}", this.nonSaltAlgorithm)); //$NON-NLS-1$
} catch (Exception e) {
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}"; //$NON-NLS-1$
msg = MessageFormat
.format(msg, EncryptionHandler.class.getName(), XmlConstants.XML_PARAM_HASH_ALGORITHM_NON_SALT,
e.getLocalizedMessage());
throw new PrivilegeException(msg, e);
}
// test hash algorithm // test hash algorithm
try { try {
hashPassword("test".toCharArray(), "test".getBytes()); //$NON-NLS-1$ hashPassword("test".toCharArray(), "test".getBytes()); //$NON-NLS-1$

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -204,8 +204,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
} }
}); });
List<RoleRep> roles = rolesStream.map(Role::asRoleRep).collect(Collectors.toList()); return rolesStream.map(Role::asRoleRep).collect(Collectors.toList());
return roles;
} }
@Override @Override
@ -228,8 +227,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
} }
}); });
List<UserRep> users = usersStream.map(User::asUserRep).collect(Collectors.toList()); return usersStream.map(User::asUserRep).collect(Collectors.toList());
return users;
} }
@Override @Override
@ -241,8 +239,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
String selUserId = selectorRep.getUserId(); String selUserId = selectorRep.getUserId();
String selUsername = selectorRep.getUsername(); String selUsername = selectorRep.getUsername();
String selFirstname = selectorRep.getFirstname(); String selFirstName = selectorRep.getFirstname();
String selLastname = selectorRep.getLastname(); String selLastName = selectorRep.getLastname();
UserState selUserState = selectorRep.getUserState(); UserState selUserState = selectorRep.getUserState();
Locale selLocale = selectorRep.getLocale(); Locale selLocale = selectorRep.getLocale();
Set<String> selRoles = selectorRep.getRoles(); Set<String> selRoles = selectorRep.getRoles();
@ -262,60 +260,30 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// selections // selections
boolean userIdSelected; boolean userIdSelected;
boolean usernameSelected; boolean usernameSelected;
boolean firstnameSelected; boolean firstNameSelected;
boolean lastnameSelected; boolean lastNameSelected;
boolean userStateSelected; boolean userStateSelected;
boolean localeSelected; boolean localeSelected;
boolean roleSelected; boolean roleSelected;
boolean propertySelected; boolean propertySelected;
// userId // userId
if (selUserId == null) userIdSelected = selUserId == null || selUserId.equals(user.getUserId());
userIdSelected = true;
else if (selUserId.equals(user.getUserId()))
userIdSelected = true;
else
userIdSelected = false;
// username // username
if (selUsername == null) usernameSelected = selUsername == null || selUsername.equals(user.getUsername());
usernameSelected = true;
else if (selUsername.equals(user.getUsername()))
usernameSelected = true;
else
usernameSelected = false;
// firstname // firstname
if (selFirstname == null) firstNameSelected = selFirstName == null || selFirstName.equals(user.getFirstname());
firstnameSelected = true;
else if (selFirstname.equals(user.getFirstname()))
firstnameSelected = true;
else
firstnameSelected = false;
// lastname // lastname
if (selLastname == null) lastNameSelected = selLastName == null || selLastName.equals(user.getLastname());
lastnameSelected = true;
else if (selLastname.equals(user.getLastname()))
lastnameSelected = true;
else
lastnameSelected = false;
// user state // user state
if (selUserState == null) userStateSelected = selUserState == null || selUserState.equals(user.getUserState());
userStateSelected = true;
else if (selUserState.equals(user.getUserState()))
userStateSelected = true;
else
userStateSelected = false;
// locale // locale
if (selLocale == null) localeSelected = selLocale == null || selLocale.equals(user.getLocale());
localeSelected = true;
else if (selLocale.equals(user.getLocale()))
localeSelected = true;
else
localeSelected = false;
// roles // roles
roleSelected = isSelectedByRole(selRoles, user.getRoles()); roleSelected = isSelectedByRole(selRoles, user.getRoles());
@ -324,7 +292,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties()); propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties());
boolean selected = boolean selected =
userIdSelected && usernameSelected && firstnameSelected && lastnameSelected && userStateSelected userIdSelected && usernameSelected && firstNameSelected && lastNameSelected && userStateSelected
&& localeSelected && roleSelected && propertySelected; && localeSelected && roleSelected && propertySelected;
if (selected) if (selected)
@ -378,11 +346,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
* null or empty, then true is returned, otherwise false * null or empty, then true is returned, otherwise false
*/ */
private boolean isSelectedByRole(Set<String> selectionRoles, Set<String> roles) { private boolean isSelectedByRole(Set<String> selectionRoles, Set<String> roles) {
return selectionRoles == null || roles.containsAll(selectionRoles);
if (selectionRoles == null)
return true;
return roles.containsAll(selectionRoles);
} }
@Override @Override
@ -531,7 +495,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
Set<String> roles = userRep.getRoles(); Set<String> roles = userRep.getRoles();
Locale locale = userRep.getLocale(); Locale locale = userRep.getLocale();
Map<String, String> properties = userRep.getProperties(); Map<String, String> properties = userRep.getProperties();
return new User(userId, userName, passwordHash, salt, firstName, lastName, state, roles, locale, properties); return new User(userId, userName, passwordHash, salt, this.encryptionHandler.getAlgorithm(),
this.encryptionHandler.getIterations(), this.encryptionHandler.getKeyLength(), firstName, lastName,
state, roles, locale, properties);
} }
@Override @Override
@ -562,26 +528,30 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
String username = existingUser.getUsername(); String username = existingUser.getUsername();
byte[] password = existingUser.getPassword(); byte[] password = existingUser.getPassword();
byte[] salt = existingUser.getSalt(); byte[] salt = existingUser.getSalt();
String firstname = existingUser.getFirstname(); String firstName = existingUser.getFirstname();
String lastname = existingUser.getLastname(); String lastName = existingUser.getLastname();
UserState userState = existingUser.getUserState(); UserState userState = existingUser.getUserState();
Set<String> roles = existingUser.getRoles(); Set<String> roles = existingUser.getRoles();
Locale locale = existingUser.getLocale(); Locale locale = existingUser.getLocale();
Map<String, String> propertyMap = existingUser.getProperties(); Map<String, String> propertyMap = existingUser.getProperties();
String hashAlgorithm = existingUser.getHashAlgorithm();
int hashIterations = existingUser.getHashIterations();
int hashKeyLength = existingUser.getHashKeyLength();
// get updated fields // get updated fields
if (StringHelper.isNotEmpty(userRep.getFirstname())) if (StringHelper.isNotEmpty(userRep.getFirstname()))
firstname = userRep.getFirstname(); firstName = userRep.getFirstname();
if (StringHelper.isNotEmpty(userRep.getLastname())) if (StringHelper.isNotEmpty(userRep.getLastname()))
lastname = userRep.getLastname(); lastName = userRep.getLastname();
if (userRep.getLocale() != null) if (userRep.getLocale() != null)
locale = userRep.getLocale(); locale = userRep.getLocale();
if (userRep.getProperties() != null && !userRep.getProperties().isEmpty()) if (userRep.getProperties() != null && !userRep.getProperties().isEmpty())
propertyMap = userRep.getProperties(); propertyMap = userRep.getProperties();
// create new user // create new user
User newUser = new User(userId, username, password, salt, firstname, lastname, userState, roles, locale, User newUser = new User(userId, username, password, salt, hashAlgorithm, hashIterations, hashKeyLength,
propertyMap); firstName, lastName, userState, roles, locale, propertyMap);
// detect privilege conflicts // detect privilege conflicts
assertNoPrivilegeConflict(newUser); assertNoPrivilegeConflict(newUser);
@ -656,7 +626,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
newRoles.add(roleName); newRoles.add(roleName);
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(),
existingUser.getSalt(), existingUser.getFirstname(), existingUser.getLastname(), existingUser.getSalt(), existingUser.getHashAlgorithm(), existingUser.getHashIterations(),
existingUser.getHashKeyLength(), existingUser.getFirstname(), existingUser.getLastname(),
existingUser.getUserState(), newRoles, existingUser.getLocale(), existingUser.getProperties()); existingUser.getUserState(), newRoles, existingUser.getLocale(), existingUser.getProperties());
// detect privilege conflicts // detect privilege conflicts
@ -699,7 +670,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
Set<String> newRoles = new HashSet<>(currentRoles); Set<String> newRoles = new HashSet<>(currentRoles);
newRoles.remove(roleName); newRoles.remove(roleName);
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(),
existingUser.getSalt(), existingUser.getFirstname(), existingUser.getLastname(), existingUser.getSalt(), existingUser.getHashAlgorithm(), existingUser.getHashIterations(),
existingUser.getHashKeyLength(), existingUser.getFirstname(), existingUser.getLastname(),
existingUser.getUserState(), newRoles, existingUser.getLocale(), existingUser.getProperties()); existingUser.getUserState(), newRoles, existingUser.getLocale(), existingUser.getProperties());
// delegate user replacement to persistence handler // delegate user replacement to persistence handler
@ -725,7 +697,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// create new user // create new user
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(),
existingUser.getSalt(), existingUser.getFirstname(), existingUser.getLastname(), existingUser.getSalt(), existingUser.getHashAlgorithm(), existingUser.getHashIterations(),
existingUser.getHashKeyLength(), existingUser.getFirstname(), existingUser.getLastname(),
existingUser.getUserState(), existingUser.getRoles(), locale, existingUser.getProperties()); existingUser.getUserState(), existingUser.getRoles(), locale, existingUser.getProperties());
// if the user is not setting their own locale, then make sure this user may set this user's locale // if the user is not setting their own locale, then make sure this user may set this user's locale
@ -776,8 +749,10 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// create new user // create new user
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), passwordHash, salt, User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), passwordHash, salt,
existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(), this.encryptionHandler.getAlgorithm(), this.encryptionHandler.getIterations(),
existingUser.getRoles(), existingUser.getLocale(), existingUser.getProperties()); this.encryptionHandler.getKeyLength(), existingUser.getFirstname(), existingUser.getLastname(),
existingUser.getUserState(), existingUser.getRoles(), existingUser.getLocale(),
existingUser.getProperties());
if (!certificate.getUsername().equals(username)) { if (!certificate.getUsername().equals(username)) {
// check that the user may change their own password // check that the user may change their own password
@ -819,7 +794,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// create new user // create new user
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(),
existingUser.getSalt(), existingUser.getFirstname(), existingUser.getLastname(), state, existingUser.getSalt(), existingUser.getHashAlgorithm(), existingUser.getHashIterations(),
existingUser.getHashKeyLength(), existingUser.getFirstname(), existingUser.getLastname(), state,
existingUser.getRoles(), existingUser.getLocale(), existingUser.getProperties()); existingUser.getRoles(), existingUser.getLocale(), existingUser.getProperties());
// validate that this user may modify this user's state // validate that this user may modify this user's state
@ -1300,18 +1276,53 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
throw new AccessDeniedException( throw new AccessDeniedException(
MessageFormat.format("User {0} has no password and may not login!", username)); //$NON-NLS-1$ MessageFormat.format("User {0} has no password and may not login!", username)); //$NON-NLS-1$
byte[] salt = user.getSalt(); byte[] salt = user.getSalt();
if (salt == null)
throw new AccessDeniedException(
MessageFormat.format("User {0} has no salt and may not login!", username)); //$NON-NLS-1$
// we only work with hashed passwords // we only work with hashed passwords
byte[] passwordHash = this.encryptionHandler.hashPassword(password, salt); byte[] passwordHash;
if (salt == null) {
passwordHash = this.encryptionHandler.hashPasswordWithoutSalt(password);
} else if (user.getHashAlgorithm() == null || user.getHashIterations() == -1 || user.getHashKeyLength() == -1) {
passwordHash = this.encryptionHandler.hashPassword(password, salt);
} else {
passwordHash = this.encryptionHandler
.hashPassword(password, salt, user.getHashAlgorithm(), user.getHashIterations(),
user.getHashKeyLength());
}
// validate password // validate password
if (!Arrays.equals(passwordHash, pwHash)) if (!Arrays.equals(passwordHash, pwHash))
throw new InvalidCredentialsException( throw new InvalidCredentialsException(
MessageFormat.format("Password is incorrect for {0}", username)); //$NON-NLS-1$ MessageFormat.format("Password is incorrect for {0}", username)); //$NON-NLS-1$
// see if we need to update the hash
if (user.getHashAlgorithm() == null || user.getHashIterations() != this.encryptionHandler.getIterations()
|| user.getHashKeyLength() != this.encryptionHandler.getKeyLength()) {
logger.warn("Updating user " + username + " due to change in hashing algorithm properties ");
// get new salt for user
salt = this.encryptionHandler.nextSalt();
// hash password
passwordHash = this.encryptionHandler.hashPassword(password, salt);
// create new user
User newUser = new User(user.getUserId(), user.getUsername(), passwordHash, salt,
this.encryptionHandler.getAlgorithm(), this.encryptionHandler.getIterations(),
this.encryptionHandler.getKeyLength(), user.getFirstname(), user.getLastname(), user.getUserState(),
user.getRoles(), user.getLocale(), user.getProperties());
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
// perform automatic persisting, if enabled
if (this.autoPersistOnUserChangesData) {
this.persistenceHandler.persist();
}
logger.info("Updated password for " + newUser.getUsername());
}
return user; return user;
} }
@ -1515,12 +1526,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
* @throws PrivilegeException * @throws PrivilegeException
* if the this method is called multiple times or an initialization exception occurs * if the this method is called multiple times or an initialization exception occurs
*/ */
public synchronized void initialize(Map<String, String> parameterMap, public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler,
EncryptionHandler encryptionHandler, PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler,
PersistenceHandler persistenceHandler, SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) {
UserChallengeHandler userChallengeHandler,
SingleSignOnHandler ssoHandler,
Map<String, Class<PrivilegePolicy>> policyMap) {
if (this.initialized) if (this.initialized)
throw new PrivilegeException("Already initialized!"); //$NON-NLS-1$ throw new PrivilegeException("Already initialized!"); //$NON-NLS-1$

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -69,6 +69,16 @@ public interface EncryptionHandler {
*/ */
byte[] nextSalt(); byte[] nextSalt();
/**
* Hashes the given password configured algorithm
*
* @param password
* the password
*
* @return the hashed password
*/
byte[] hashPasswordWithoutSalt(final char[] password);
/** /**
* Hashes the given password with the given salt with the configured algorithm * Hashes the given password with the given salt with the configured algorithm
* *
@ -81,6 +91,24 @@ public interface EncryptionHandler {
*/ */
byte[] hashPassword(final char[] password, final byte[] salt); byte[] hashPassword(final char[] password, final byte[] salt);
/**
* Hashes the given password with the given salt and algorithm properties
*
* @param password
* the password
* @param salt
* the salt
* @param algorithm
* the algorithm
* @param iterations
* the iterations
* @param keyLength
* the keyLength
*
* @return the hashed password
*/
byte[] hashPassword(final char[] password, final byte[] salt, String algorithm, int iterations, int keyLength);
/** /**
* Initialize the concrete {@link EncryptionHandler}. The passed parameter map contains any configuration the * Initialize the concrete {@link EncryptionHandler}. The passed parameter map contains any configuration the
* concrete {@link EncryptionHandler} might need * concrete {@link EncryptionHandler} might need

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,7 +17,7 @@ package li.strolch.privilege.helper;
/** /**
* The constants used in parsing XML documents which contain the configuration for Privilege * The constants used in parsing XML documents which contain the configuration for Privilege
* *
* @author Robert von Burg <eitch@eitchnet.ch> * @author Robert von Burg <eitch@eitchnet.ch>
*/ */
@SuppressWarnings("nls") @SuppressWarnings("nls")
@ -248,6 +248,11 @@ public class XmlConstants {
*/ */
public static final String XML_PARAM_HASH_ALGORITHM = "hashAlgorithm"; public static final String XML_PARAM_HASH_ALGORITHM = "hashAlgorithm";
/**
* XML_PARAM_HASH_ALGORITHM_NON_SALT = "hashAlgorithmNonSalt" :
*/
public static final String XML_PARAM_HASH_ALGORITHM_NON_SALT = "hashAlgorithmNonSalt";
/** /**
* XML_PARAM_HASH_ALGORITHM = "hashAlgorithm" : * XML_PARAM_HASH_ALGORITHM = "hashAlgorithm" :
*/ */

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -30,12 +30,12 @@ import li.strolch.utils.helper.StringHelper;
/** /**
* This class defines the actual login information for a given user which can be granted privileges. Every user is * This class defines the actual login information for a given user which can be granted privileges. Every user is
* granted a set of {@link Role}s and has a {@link UserState} including detail information like first name and lastname * granted a set of {@link Role}s and has a {@link UserState} including detail information like first name and lastname
* *
* <p> * <p>
* Note: This is an internal object which is not to be serialized or passed to clients, {@link UserRep}s are used for * Note: This is an internal object which is not to be serialized or passed to clients, {@link UserRep}s are used for
* that * that
* </p> * </p>
* *
* @author Robert von Burg <eitch@eitchnet.ch> * @author Robert von Burg <eitch@eitchnet.ch>
*/ */
public final class User { public final class User {
@ -45,6 +45,9 @@ public final class User {
private final String username; private final String username;
private final byte[] password; private final byte[] password;
private final byte[] salt; private final byte[] salt;
private final String hashAlgorithm;
private final int hashIterations;
private final int hashKeyLength;
private final String firstname; private final String firstname;
private final String lastname; private final String lastname;
@ -59,28 +62,37 @@ public final class User {
/** /**
* Default constructor * Default constructor
* *
* @param userId * @param userId
* the user's id * the user's id
* @param username * @param username
* the user's login name * the user's login name
* @param password * @param password
* the user's password (hashed) * the user's password (hashed)
* @param salt
* the password salt
* @param hashAlgorithm
* the algorithm for the hash
* @param hashIterations
* the nr of iterations for hashing
* @param hashKeyLength
* the hash key length
* @param firstname * @param firstname
* the user's first name * the user's first name
* @param lastname * @param lastname
* the user's lastname * the user's lastname
* @param userState * @param userState
* the user's {@link UserState} * the user's {@link UserState}
* @param roles * @param roles
* the set of {@link Role}s assigned to this user * the set of {@link Role}s assigned to this user
* @param locale * @param locale
* the user's {@link Locale} * the user's {@link Locale}
* @param propertyMap * @param propertyMap
* a {@link Map} containing string value pairs of properties for this user * a {@link Map} containing string value pairs of properties for this user
*/ */
public User(String userId, String username, byte[] password, byte[] salt, String firstname, String lastname, public User(String userId, String username, byte[] password, byte[] salt, String hashAlgorithm, int hashIterations,
UserState userState, Set<String> roles, Locale locale, Map<String, String> propertyMap) { int hashKeyLength, String firstname, String lastname, UserState userState, Set<String> roles, Locale locale,
Map<String, String> propertyMap) {
if (StringHelper.isEmpty(userId)) { if (StringHelper.isEmpty(userId)) {
throw new PrivilegeException("No UserId defined!"); //$NON-NLS-1$ throw new PrivilegeException("No UserId defined!"); //$NON-NLS-1$
@ -100,7 +112,7 @@ public final class User {
} }
} }
// password may be null, meaning not able to login // password, salt and hash* may be null, meaning not able to login
// roles may be null, meaning not able to login and must be added later // roles may be null, meaning not able to login and must be added later
// locale may be null, meaning use system default // locale may be null, meaning use system default
// properties may be null, meaning no properties // properties may be null, meaning no properties
@ -110,6 +122,11 @@ public final class User {
this.username = username; this.username = username;
this.password = password; this.password = password;
this.salt = salt; this.salt = salt;
this.hashAlgorithm = hashAlgorithm;
this.hashIterations = hashIterations;
this.hashKeyLength = hashKeyLength;
this.userState = userState; this.userState = userState;
this.firstname = firstname; this.firstname = firstname;
@ -147,7 +164,7 @@ public final class User {
/** /**
* Returns the hashed password for this {@link User} * Returns the hashed password for this {@link User}
* *
* @return the hashed password for this {@link User} * @return the hashed password for this {@link User}
*/ */
public byte[] getPassword() { public byte[] getPassword() {
@ -156,13 +173,40 @@ public final class User {
/** /**
* Return the salt for this {@link User} * Return the salt for this {@link User}
* *
* @return the salt for this {@link User} * @return the salt for this {@link User}
*/ */
public byte[] getSalt() { public byte[] getSalt() {
return this.salt; return this.salt;
} }
/**
* Return the hash algorithm
*
* @return the hash algorithm
*/
public String getHashAlgorithm() {
return this.hashAlgorithm;
}
/**
* Return the hashIterations
*
* @return hashIterations
*/
public int getHashIterations() {
return this.hashIterations;
}
/**
* Return the hashKeyLength
*
* @return hashKeyLength
*/
public int getHashKeyLength() {
return this.hashKeyLength;
}
/** /**
* @return the first name * @return the first name
*/ */
@ -193,10 +237,10 @@ public final class User {
/** /**
* Returns true if this user has the specified role * Returns true if this user has the specified role
* *
* @param role * @param role
* the name of the {@link Role} to check for * the name of the {@link Role} to check for
* *
* @return true if the this user has the specified role * @return true if the this user has the specified role
*/ */
public boolean hasRole(String role) { public boolean hasRole(String role) {
@ -212,10 +256,10 @@ public final class User {
/** /**
* Returns the property with the given key * Returns the property with the given key
* *
* @param key * @param key
* the key for which the property is to be returned * the key for which the property is to be returned
* *
* @return the property with the given key, or null if the property is not defined * @return the property with the given key, or null if the property is not defined
*/ */
public String getProperty(String key) { public String getProperty(String key) {
@ -224,7 +268,7 @@ public final class User {
/** /**
* Returns the {@link Set} of keys of all properties * Returns the {@link Set} of keys of all properties
* *
* @return the {@link Set} of keys of all properties * @return the {@link Set} of keys of all properties
*/ */
public Set<String> getPropertyKeySet() { public Set<String> getPropertyKeySet() {
@ -233,7 +277,7 @@ public final class User {
/** /**
* Returns the map of properties * Returns the map of properties
* *
* @return the map of properties * @return the map of properties
*/ */
public Map<String, String> getProperties() { public Map<String, String> getProperties() {
@ -250,7 +294,7 @@ public final class User {
/** /**
* Returns a string representation of this object displaying its concrete type and its values * Returns a string representation of this object displaying its concrete type and its values
* *
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@SuppressWarnings("nls") @SuppressWarnings("nls")

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -16,6 +16,7 @@
package li.strolch.privilege.xml; package li.strolch.privilege.xml;
import java.io.File; import java.io.File;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -35,10 +36,6 @@ public class PrivilegeUsersDomWriter {
private List<User> users; private List<User> users;
private File modelFile; private File modelFile;
/**
* @param users
* @param modelFile
*/
public PrivilegeUsersDomWriter(List<User> users, File modelFile) { public PrivilegeUsersDomWriter(List<User> users, File modelFile) {
this.users = users; this.users = users;
this.modelFile = modelFile; this.modelFile = modelFile;
@ -51,7 +48,7 @@ public class PrivilegeUsersDomWriter {
Element rootElement = doc.createElement(XmlConstants.XML_USERS); Element rootElement = doc.createElement(XmlConstants.XML_USERS);
doc.appendChild(rootElement); doc.appendChild(rootElement);
this.users.stream().sorted((u1, u2) -> u1.getUserId().compareTo(u2.getUserId())).forEach(user -> { this.users.stream().sorted(Comparator.comparing(User::getUserId)).forEach(user -> {
// create the user element // create the user element
Element userElement = doc.createElement(XmlConstants.XML_USER); Element userElement = doc.createElement(XmlConstants.XML_USER);
@ -59,10 +56,7 @@ public class PrivilegeUsersDomWriter {
userElement.setAttribute(XmlConstants.XML_ATTR_USER_ID, user.getUserId()); userElement.setAttribute(XmlConstants.XML_ATTR_USER_ID, user.getUserId());
userElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, user.getUsername()); userElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, user.getUsername());
if (user.getPassword() != null) writePassword(user, userElement);
userElement.setAttribute(XmlConstants.XML_ATTR_PASSWORD, StringHelper.toHexString(user.getPassword()));
if (user.getSalt() != null)
userElement.setAttribute(XmlConstants.XML_ATTR_SALT, StringHelper.toHexString(user.getSalt()));
// add first name element // add first name element
if (StringHelper.isNotEmpty(user.getFirstname())) { if (StringHelper.isNotEmpty(user.getFirstname())) {
@ -113,4 +107,25 @@ public class PrivilegeUsersDomWriter {
// write the container file to disk // write the container file to disk
XmlHelper.writeDocument(doc, this.modelFile); XmlHelper.writeDocument(doc, this.modelFile);
} }
private void writePassword(User user, Element userElement) {
if (user.getPassword() != null && user.getSalt() != null && user.getHashAlgorithm() != null
&& user.getHashIterations() != -1 && user.getHashKeyLength() != -1) {
String algo = user.getHashAlgorithm() + "," + user.getHashIterations() + "," + user.getHashKeyLength();
String hash = StringHelper.toHexString(user.getSalt());
String password = StringHelper.toHexString(user.getPassword());
String passwordS = "$" + algo + "$" + hash + "$" + password;
userElement.setAttribute(XmlConstants.XML_ATTR_PASSWORD, passwordS);
} else {
if (user.getPassword() != null)
userElement.setAttribute(XmlConstants.XML_ATTR_PASSWORD, StringHelper.toHexString(user.getPassword()));
if (user.getSalt() != null)
userElement.setAttribute(XmlConstants.XML_ATTR_SALT, StringHelper.toHexString(user.getSalt()));
}
}
} }

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -117,6 +117,9 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
String username; String username;
byte[] password; byte[] password;
byte[] salt; byte[] salt;
String hashAlgorithm;
int hashIterations = -1;
int hashKeyLength = -1;
String firstName; String firstName;
String lastname; String lastname;
UserState userState; UserState userState;
@ -137,12 +140,46 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
if (qName.equals(XmlConstants.XML_USER)) { if (qName.equals(XmlConstants.XML_USER)) {
this.userId = attributes.getValue(XmlConstants.XML_ATTR_USER_ID); this.userId = attributes.getValue(XmlConstants.XML_ATTR_USER_ID);
this.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME); this.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME);
String passwordS = attributes.getValue(XmlConstants.XML_ATTR_PASSWORD);
if (!StringHelper.isEmpty(passwordS)) String password = attributes.getValue(XmlConstants.XML_ATTR_PASSWORD);
this.password = StringHelper.fromHexString(passwordS); String salt = attributes.getValue(XmlConstants.XML_ATTR_SALT);
String saltS = attributes.getValue(XmlConstants.XML_ATTR_SALT); parsePassword(password, salt);
if (!StringHelper.isEmpty(saltS)) }
this.salt = StringHelper.fromHexString(saltS); }
private void parsePassword(String passwordS, String salt) {
if (StringHelper.isNotEmpty(salt))
this.salt = StringHelper.fromHexString(salt);
if (StringHelper.isEmpty(passwordS))
return;
if (!passwordS.startsWith("$")) {
this.password = StringHelper.fromHexString(passwordS);
} else {
String[] parts = passwordS.split("\\$");
if (parts.length != 4) {
logger.error("Illegal password " + passwordS + ": Starts with $, but does not have 3 parts!");
} else {
String hashAlgorithm = parts[1];
String[] hashParts = hashAlgorithm.split(",");
if (hashParts.length != 3) {
logger.error("Illegal password " + passwordS
+ ": hashAlgorithm part does not have 3 parts separated by comma!");
} else {
this.hashAlgorithm = hashParts[0];
this.hashIterations = Integer.parseInt(hashParts[1]);
this.hashKeyLength = Integer.parseInt(hashParts[2]);
this.salt = StringHelper.fromHexString(parts[2]);
this.password = StringHelper.fromHexString(parts[3]);
}
}
} }
} }
@ -154,30 +191,51 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
@Override @Override
public void endElement(String uri, String localName, String qName) throws SAXException { public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals(XmlConstants.XML_FIRSTNAME)) { switch (qName) {
this.firstName = this.text.toString().trim(); case XmlConstants.XML_FIRSTNAME:
} else if (qName.equals(XmlConstants.XML_LASTNAME)) {
this.lastname = this.text.toString().trim();
} else if (qName.equals(XmlConstants.XML_STATE)) {
this.userState = UserState.valueOf(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_LOCALE)) {
this.locale = new Locale(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_ROLE)) {
this.userRoles.add(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_ROLES)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_PARAMETER)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_USER)) {
User user = new User(this.userId, this.username, this.password, this.salt, this.firstName, this.firstName = this.text.toString().trim();
this.lastname, this.userState, this.userRoles, this.locale, this.parameters); break;
case XmlConstants.XML_LASTNAME:
this.lastname = this.text.toString().trim();
break;
case XmlConstants.XML_STATE:
this.userState = UserState.valueOf(this.text.toString().trim());
break;
case XmlConstants.XML_LOCALE:
this.locale = new Locale(this.text.toString().trim());
break;
case XmlConstants.XML_ROLE:
this.userRoles.add(this.text.toString().trim());
break;
case XmlConstants.XML_USER:
User user = new User(this.userId, this.username, this.password, this.salt, this.hashAlgorithm,
hashIterations, hashKeyLength, this.firstName, this.lastname, this.userState, this.userRoles,
this.locale, this.parameters);
logger.info(MessageFormat.format("New User: {0}", user)); //$NON-NLS-1$ logger.info(MessageFormat.format("New User: {0}", user)); //$NON-NLS-1$
getUsers().add(user); getUsers().add(user);
} else { break;
throw new IllegalArgumentException("Unhandled tag " + qName);
default:
if (!(qName.equals(XmlConstants.XML_ROLES) //
|| qName.equals(XmlConstants.XML_PARAMETER) //
|| qName.equals(XmlConstants.XML_PARAMETERS))) {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
break;
} }
} }
@ -191,21 +249,27 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
class PropertyParser extends ElementParserAdapter { class PropertyParser extends ElementParserAdapter {
// <Property name="organizationalUnit" value="Development" /> // <Property name="organizationalUnit" value="Development" />
public Map<String, String> parameterMap = new HashMap<>(); public Map<String, String> parameterMap = new HashMap<>();
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { throws SAXException {
if (qName.equals(XmlConstants.XML_PROPERTY)) {
switch (qName) {
case XmlConstants.XML_PROPERTY:
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME); String key = attributes.getValue(XmlConstants.XML_ATTR_NAME);
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE); String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE);
this.parameterMap.put(key, value); this.parameterMap.put(key, value);
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) { break;
// NO-OP
} else { default:
throw new IllegalArgumentException("Unhandled tag " + qName);
if (!qName.equals(XmlConstants.XML_PROPERTIES)) {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
} }
} }

View File

@ -70,6 +70,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
private static final String ROLE_PRIVILEGE_ADMIN = "PrivilegeAdmin"; private static final String ROLE_PRIVILEGE_ADMIN = "PrivilegeAdmin";
private static final String PRIVILEGE_USER_ACCESS = "UserAccessPrivilege"; private static final String PRIVILEGE_USER_ACCESS = "UserAccessPrivilege";
private static final String ADMIN = "admin"; private static final String ADMIN = "admin";
private static final String ADMIN2 = "admin2";
private static final char[] PASS_ADMIN = "admin".toCharArray(); private static final char[] PASS_ADMIN = "admin".toCharArray();
private static final String BOB = "bob"; private static final String BOB = "bob";
private static final String TED = "ted"; private static final String TED = "ted";
@ -117,6 +118,15 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
} }
} }
@Test
public void testAuthenticationAdmin2Ok() throws Exception {
try {
login(ADMIN2, ArraysHelper.copyOf(PASS_ADMIN));
} finally {
logout();
}
}
@Test @Test
public void testFailAuthenticationNOk() throws Exception { public void testFailAuthenticationNOk() throws Exception {
this.exception.expect(AccessDeniedException.class); this.exception.expect(AccessDeniedException.class);
@ -328,7 +338,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
UserRep selectorRep = new UserRep(null, null, null, null, null, UserRep selectorRep = new UserRep(null, null, null, null, null,
new HashSet<>(Collections.singletonList("PrivilegeAdmin")), null, null); new HashSet<>(Collections.singletonList("PrivilegeAdmin")), null, null);
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep); List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
assertEquals(1, users.size()); assertEquals(2, users.size());
assertEquals(ADMIN, users.get(0).getUsername()); assertEquals(ADMIN, users.get(0).getUsername());
} finally { } finally {

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -36,7 +36,6 @@ import li.strolch.privilege.xml.*;
import li.strolch.utils.helper.FileHelper; import li.strolch.utils.helper.FileHelper;
import li.strolch.utils.helper.StringHelper; import li.strolch.utils.helper.StringHelper;
import li.strolch.utils.helper.XmlHelper; import li.strolch.utils.helper.XmlHelper;
import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -52,23 +51,19 @@ public class XmlTest {
private static final String SRC_TEST = "src/test/resources/config/"; private static final String SRC_TEST = "src/test/resources/config/";
private static final Logger logger = LoggerFactory.getLogger(XmlTest.class); private static final Logger logger = LoggerFactory.getLogger(XmlTest.class);
/**
* @throws Exception
* if something goes wrong
*/
@BeforeClass @BeforeClass
public static void init() throws Exception { public static void init() {
cleanUp(); cleanUp();
File tmpDir = new File("target/test"); File tmpDir = new File("target/test");
if (tmpDir.exists()) if (tmpDir.exists())
FileHelper.deleteFile(tmpDir, false); FileHelper.deleteFile(tmpDir, false);
tmpDir.mkdirs(); if (!tmpDir.mkdirs())
throw new IllegalStateException("Could not create temp dir " + tmpDir.getAbsolutePath());
} }
@AfterClass public static void cleanUp() {
public static void cleanUp() throws Exception {
File tmpDir = new File("target/test"); File tmpDir = new File("target/test");
if (!tmpDir.exists()) if (!tmpDir.exists())
@ -161,7 +156,7 @@ public class XmlTest {
List<User> users = xmlHandler.getUsers(); List<User> users = xmlHandler.getUsers();
assertNotNull(users); assertNotNull(users);
assertEquals(3, users.size()); assertEquals(4, users.size());
// //
// users // users
@ -319,15 +314,15 @@ public class XmlTest {
propertyMap.put("prop1", "value1"); propertyMap.put("prop1", "value1");
userRoles = new HashSet<>(); userRoles = new HashSet<>();
userRoles.add("role1"); userRoles.add("role1");
User user1 = new User("1", "user1", "blabla".getBytes(), "blabla".getBytes(), "Bob", "White", User user1 = new User("1", "user1", "blabla".getBytes(), "blabla".getBytes(), "PBKDF2WithHmacSHA512", 10000,
UserState.DISABLED, userRoles, Locale.ENGLISH, propertyMap); 256, "Bob", "White", UserState.DISABLED, userRoles, Locale.ENGLISH, propertyMap);
users.add(user1); users.add(user1);
propertyMap = new HashMap<>(); propertyMap = new HashMap<>();
propertyMap.put("prop2", "value2"); propertyMap.put("prop2", "value2");
userRoles = new HashSet<>(); userRoles = new HashSet<>();
userRoles.add("role2"); userRoles.add("role2");
User user2 = new User("2", "user2", "haha".getBytes(), "haha".getBytes(), "Leonard", "Sheldon", User user2 = new User("2", "user2", "haha".getBytes(), "haha".getBytes(), null, -1, -1, "Leonard", "Sheldon",
UserState.ENABLED, userRoles, Locale.ENGLISH, propertyMap); UserState.ENABLED, userRoles, Locale.ENGLISH, propertyMap);
users.add(user2); users.add(user2);

View File

@ -23,7 +23,7 @@ public class DummySsoHandler implements SingleSignOnHandler {
Set<String> roles = Arrays.stream(map.get("roles").split(",")).map(String::trim).collect(Collectors.toSet()); Set<String> roles = Arrays.stream(map.get("roles").split(",")).map(String::trim).collect(Collectors.toSet());
Map<String, String> properties = new HashMap<>(); Map<String, String> properties = new HashMap<>();
return new User(map.get("userId"), map.get("username"), null, null, map.get("firstName"), map.get("lastName"), return new User(map.get("userId"), map.get("username"), null, null, null, -1, -1, map.get("firstName"),
UserState.ENABLED, roles, Locale.ENGLISH, properties); map.get("lastName"), UserState.ENABLED, roles, Locale.ENGLISH, properties);
} }
} }

View File

@ -1,39 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Users> <Users>
<User userId="1" username="admin" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e"> <User userId="1" username="admin" password="$PBKDF2WithHmacSHA512,10000,256$61646d696e$cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344">
<Firstname>Application</Firstname> <Firstname>Application</Firstname>
<Lastname>Administrator</Lastname> <Lastname>Administrator</Lastname>
<State>ENABLED</State> <State>ENABLED</State>
<Locale>en_GB</Locale> <Locale>en_GB</Locale>
<Roles> <Roles>
<Role>PrivilegeAdmin</Role> <Role>PrivilegeAdmin</Role>
<Role>AppUser</Role> <Role>AppUser</Role>
</Roles> </Roles>
<Properties> <Properties>
<Property name="organization" value="eitchnet.ch" /> <Property name="organization" value="eitchnet.ch"/>
<Property name="organizationalUnit" value="Development" /> <Property name="organizationalUnit" value="Development"/>
</Properties> </Properties>
</User> </User>
<User userId="2" username="system_admin"> <User userId="1" username="admin2" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
<Firstname>System User</Firstname> <Firstname>Application</Firstname>
<Lastname>Administrator</Lastname> <Lastname>Administrator</Lastname>
<State>SYSTEM</State> <State>ENABLED</State>
<Locale>en_GB</Locale> <Locale>en_GB</Locale>
<Roles> <Roles>
<Role>system_admin_privileges</Role> <Role>PrivilegeAdmin</Role>
</Roles> <Role>AppUser</Role>
</User> </Roles>
<Properties>
<Property name="organization" value="eitchnet.ch"/>
<Property name="organizationalUnit" value="Development"/>
</Properties>
</User>
<User userId="3" username="system_admin2"> <User userId="2" username="system_admin">
<Firstname>System User</Firstname> <Firstname>System User</Firstname>
<Lastname>Administrator</Lastname> <Lastname>Administrator</Lastname>
<State>SYSTEM</State> <State>SYSTEM</State>
<Locale>en_GB</Locale> <Locale>en_GB</Locale>
<Roles> <Roles>
<Role>system_admin_privileges</Role> <Role>system_admin_privileges</Role>
</Roles> </Roles>
</User> </User>
<User userId="3" username="system_admin2">
<Firstname>System User</Firstname>
<Lastname>Administrator</Lastname>
<State>SYSTEM</State>
<Locale>en_GB</Locale>
<Roles>
<Role>system_admin_privileges</Role>
</Roles>
</User>
</Users> </Users>