Merge branch 'develop' into release/2.1
This commit is contained in:
commit
42ee3de41f
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package li.strolch.policy;
|
||||
|
||||
import static li.strolch.model.StrolchModelConstants.PolicyConstants.PARAM_ORDER;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchAgent;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
|
@ -27,6 +25,8 @@ import li.strolch.service.api.Command;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static li.strolch.model.StrolchModelConstants.PolicyConstants.PARAM_ORDER;
|
||||
|
||||
/**
|
||||
* Interface for all Strolch policies, which are instantiated by the {@link PolicyHandler}
|
||||
*
|
||||
|
@ -103,6 +103,14 @@ public abstract class StrolchPolicy {
|
|||
return this.tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this TX is still open, or committing, and thus can still be used
|
||||
* @return true if this TX is still open, or committing, and thus can still be used
|
||||
*/
|
||||
protected boolean isTxOpen() {
|
||||
return this.tx.isOpen() || this.tx.isCommitting();
|
||||
}
|
||||
|
||||
protected Order getOrder(IActivityElement element) {
|
||||
return tx().getOrderByRelation(element.getRootElement(), PARAM_ORDER, true);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import static java.lang.Boolean.parseBoolean;
|
|||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH;
|
||||
import static li.strolch.privilege.helper.XmlConstants.XML_PARAM_BASE_PATH;
|
||||
import static li.strolch.privilege.helper.XmlConstants.PARAM_BASE_PATH;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -126,7 +126,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
|
||||
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
|
||||
File configPath = runtimeConfig.getConfigPath();
|
||||
xmlParams.put(XML_PARAM_BASE_PATH, configPath.getPath());
|
||||
xmlParams.put(PARAM_BASE_PATH, configPath.getPath());
|
||||
}
|
||||
|
||||
return new PrivilegeInitializer(getScheduledExecutor(getName())).initializeFromXml(containerModel);
|
||||
|
|
|
@ -9,7 +9,7 @@ import li.strolch.model.StrolchRootElement;
|
|||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
|
@ -20,10 +20,10 @@ public class ModelPrivilege implements PrivilegePolicy {
|
|||
/**
|
||||
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
|
||||
*
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, IPrivilege, Restrictable)
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Privilege, Restrictable)
|
||||
*/
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
@ -31,15 +31,15 @@ public class ModelPrivilege implements PrivilegePolicy {
|
|||
/**
|
||||
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
|
||||
*
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, IPrivilege, Restrictable)
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Privilege, Restrictable)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
preValidate(privilege, restrictable);
|
||||
|
|
|
@ -13,21 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.rest;
|
||||
|
||||
import static java.util.function.Function.identity;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_GET_SESSION;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_INVALIDATE_SESSION;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
package li.strolch.runtime.sessions;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
|
@ -38,13 +24,25 @@ import li.strolch.privilege.model.Certificate;
|
|||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.SimpleRestrictable;
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.rest.model.UserSession;
|
||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.function.Function.identity;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_GET_SESSION;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_INVALIDATE_SESSION;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -52,12 +50,10 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
|
||||
public static final String PARAM_SESSION_TTL_MINUTES = "session.ttl.minutes";
|
||||
public static final String PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES = "session.maxKeepAlive.minutes";
|
||||
public static final String PARAM_SESSION_RELOAD_SESSIONS = "session.reload";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
|
||||
private PrivilegeHandler privilegeHandler;
|
||||
private final Map<String, Certificate> certificateMap;
|
||||
private boolean reloadSessions;
|
||||
private int sessionTtlMinutes;
|
||||
private int maxKeepAliveMinutes;
|
||||
|
||||
|
@ -74,6 +70,29 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
return this.sessionTtlMinutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshSessions() {
|
||||
Map<String, Certificate> certificates;
|
||||
try {
|
||||
certificates = runAsAgentWithResult(ctx -> {
|
||||
Certificate cert = ctx.getCertificate();
|
||||
return this.privilegeHandler.getPrivilegeHandler().getCertificates(cert).stream()
|
||||
.filter(c -> !c.getUserState().isSystem())
|
||||
.collect(Collectors.toMap(Certificate::getAuthToken, identity()));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to refresh sessions!", e);
|
||||
}
|
||||
|
||||
synchronized (this.certificateMap) {
|
||||
this.certificateMap.clear();
|
||||
this.certificateMap.putAll(certificates);
|
||||
}
|
||||
checkSessionsForTimeout();
|
||||
logger.info("Restored " + certificates.size() + " sessions of which " +
|
||||
(certificates.size() - this.certificateMap.size()) + " had timed out and were removed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionMaxKeepAliveMinutes() {
|
||||
return this.maxKeepAliveMinutes;
|
||||
|
@ -89,30 +108,14 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
this.sessionTtlMinutes = configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30);
|
||||
this.maxKeepAliveMinutes = configuration.getInt(PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES,
|
||||
Math.max(this.sessionTtlMinutes, 30));
|
||||
this.reloadSessions = configuration.getBoolean(PARAM_SESSION_RELOAD_SESSIONS, false);
|
||||
super.initialize(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
||||
this.certificateMap.clear();
|
||||
|
||||
if (this.reloadSessions) {
|
||||
Map<String, Certificate> certificates = runAsAgentWithResult(ctx -> {
|
||||
Certificate cert = ctx.getCertificate();
|
||||
return this.privilegeHandler.getPrivilegeHandler()
|
||||
.getCertificates(cert)
|
||||
.stream()
|
||||
.filter(c -> !c.getUserState().isSystem())
|
||||
.collect(Collectors.toMap(Certificate::getAuthToken, identity()));
|
||||
});
|
||||
this.certificateMap.putAll(certificates);
|
||||
|
||||
checkSessionsForTimeout();
|
||||
logger.info("Restored " + certificates.size() + " sessions of which " + (certificates.size()
|
||||
- this.certificateMap.size()) + " had timed out and were removed.");
|
||||
}
|
||||
refreshSessions();
|
||||
|
||||
this.validateSessionsTask = getScheduledExecutor("SessionHandler").scheduleWithFixedDelay(
|
||||
this::checkSessionsForTimeout, 5, 1, TimeUnit.MINUTES);
|
||||
|
@ -126,27 +129,6 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
if (this.validateSessionsTask != null)
|
||||
this.validateSessionsTask.cancel(true);
|
||||
|
||||
if (this.reloadSessions) {
|
||||
|
||||
if (this.privilegeHandler != null)
|
||||
persistSessions();
|
||||
|
||||
} else {
|
||||
Map<String, Certificate> certificateMap;
|
||||
synchronized (this.certificateMap) {
|
||||
certificateMap = new HashMap<>(this.certificateMap);
|
||||
this.certificateMap.clear();
|
||||
}
|
||||
for (Certificate certificate : certificateMap.values()) {
|
||||
try {
|
||||
this.privilegeHandler.invalidate(certificate);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to invalidate certificate " + certificate, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.privilegeHandler = null;
|
||||
super.stop();
|
||||
}
|
||||
|
@ -321,8 +303,8 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
}
|
||||
|
||||
private void checkSessionsForTimeout() {
|
||||
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minus(this.maxKeepAliveMinutes, ChronoUnit.MINUTES);
|
||||
ZonedDateTime timeOutTime = ZonedDateTime.now().minus(this.sessionTtlMinutes, ChronoUnit.MINUTES);
|
||||
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minusMinutes(this.maxKeepAliveMinutes);
|
||||
ZonedDateTime timeOutTime = ZonedDateTime.now().minusMinutes(this.sessionTtlMinutes);
|
||||
|
||||
Map<String, Certificate> certificateMap = getCertificateMapCopy();
|
||||
for (Certificate certificate : certificateMap.values()) {
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.rest;
|
||||
package li.strolch.runtime.sessions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -24,7 +24,6 @@ import li.strolch.privilege.base.PrivilegeException;
|
|||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.rest.model.UserSession;
|
||||
|
||||
/**
|
||||
* The {@link StrolchSessionHandler} implements session management. It authenticates, validates and invalidates session
|
||||
|
@ -34,6 +33,11 @@ import li.strolch.rest.model.UserSession;
|
|||
*/
|
||||
public interface StrolchSessionHandler {
|
||||
|
||||
/**
|
||||
* Refreshes the sessions from the {@link li.strolch.runtime.privilege.PrivilegeHandler}
|
||||
*/
|
||||
void refreshSessions();
|
||||
|
||||
/**
|
||||
* Returns the time to live for a session in minutes
|
||||
*
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.rest.model;
|
||||
package li.strolch.runtime.sessions;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Locale;
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -213,10 +213,10 @@ public enum State {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if {@link #PLANNED} or {@link #EXECUTION} or {@link #WARNING} or {@link #ERROR}
|
||||
* @return true if {@link #PLANNED} or {@link #EXECUTION} or {@link #WARNING} or {@link #ERROR} or {@link #STOPPED}
|
||||
*/
|
||||
public boolean canSetToError() {
|
||||
return this == PLANNED || this == EXECUTION || this == WARNING || this == ERROR;
|
||||
return this == PLANNED || this == EXECUTION || this == WARNING || this == ERROR || this == STOPPED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,8 +282,8 @@ public enum State {
|
|||
// execution
|
||||
if (states.contains(EXECUTABLE) || states.contains(EXECUTION))
|
||||
return EXECUTION;
|
||||
if (states.contains(EXECUTED) && (states.contains(CREATED) || states.contains(PLANNING) || states.contains(
|
||||
PLANNED)))
|
||||
if (states.contains(EXECUTED) &&
|
||||
(states.contains(CREATED) || states.contains(PLANNING) || states.contains(PLANNED)))
|
||||
return EXECUTION;
|
||||
|
||||
// executed
|
||||
|
|
|
@ -740,6 +740,8 @@ public class Activity extends AbstractStrolchRootElement
|
|||
|
||||
@Override
|
||||
public Activity ensureModifiable() {
|
||||
if (!this.isRootElement())
|
||||
throw new IllegalStateException("Only call this method on the root element!");
|
||||
if (isReadOnly())
|
||||
return getClone(true);
|
||||
return this;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package li.strolch.model.json;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
@ -11,6 +9,8 @@ import li.strolch.privilege.model.RoleRep;
|
|||
import li.strolch.privilege.model.UserRep;
|
||||
import li.strolch.privilege.model.UserState;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PrivilegeElementFromJsonVisitor {
|
||||
|
||||
public UserRep userRepFromJson(String string) {
|
||||
|
@ -32,11 +32,12 @@ public class PrivilegeElementFromJsonVisitor {
|
|||
|
||||
String name = nameE == null ? null : nameE.getAsString().trim();
|
||||
|
||||
List<PrivilegeRep> privileges = new ArrayList<>();
|
||||
Map<String, PrivilegeRep> privileges = new HashMap<>();
|
||||
if (privilegesE != null) {
|
||||
JsonArray privilegesArr = privilegesE.getAsJsonArray();
|
||||
for (JsonElement privilegeE : privilegesArr) {
|
||||
privileges.add(privilegeRepFromJson(privilegeE.getAsJsonObject()));
|
||||
PrivilegeRep privilegeRep = privilegeRepFromJson(privilegeE.getAsJsonObject());
|
||||
privileges.put(privilegeRep.getName(), privilegeRep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +83,7 @@ public class PrivilegeElementFromJsonVisitor {
|
|||
JsonElement lastNameE = jsonObject.get("lastname");
|
||||
JsonElement userStateE = jsonObject.get("userState");
|
||||
JsonElement localeE = jsonObject.get("locale");
|
||||
JsonElement groupsE = jsonObject.get("groups");
|
||||
JsonElement rolesE = jsonObject.get("roles");
|
||||
JsonElement propertiesE = jsonObject.get("properties");
|
||||
|
||||
|
@ -90,16 +92,11 @@ public class PrivilegeElementFromJsonVisitor {
|
|||
String firstname = firstNameE == null ? null : firstNameE.getAsString().trim();
|
||||
String lastname = lastNameE == null ? null : lastNameE.getAsString().trim();
|
||||
UserState userState = userStateE == null ? null : UserState.valueOf(userStateE.getAsString().trim());
|
||||
Locale locale = localeE == null ? null : new Locale(localeE.getAsString().trim());
|
||||
Locale locale = localeE == null ? null : Locale.forLanguageTag(localeE.getAsString().trim());
|
||||
|
||||
Set<String> roles = null;
|
||||
if (rolesE != null) {
|
||||
roles = new HashSet<>();
|
||||
JsonArray rolesArr = rolesE.getAsJsonArray();
|
||||
for (JsonElement role : rolesArr) {
|
||||
roles.add(role.getAsString().trim());
|
||||
}
|
||||
}
|
||||
Set<String> groups = jsonArrayToSet(groupsE);
|
||||
|
||||
Set<String> roles = jsonArrayToSet(rolesE);
|
||||
|
||||
Map<String, String> properties = null;
|
||||
if (propertiesE != null) {
|
||||
|
@ -111,6 +108,19 @@ public class PrivilegeElementFromJsonVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
return new UserRep(userId, username, firstname, lastname, userState, roles, locale, properties, null);
|
||||
return new UserRep(userId, username, firstname, lastname, userState, groups, roles, locale, properties, null);
|
||||
}
|
||||
|
||||
private Set<String> jsonArrayToSet(JsonElement array) {
|
||||
if (array == null)
|
||||
return Set.of();
|
||||
|
||||
Set<String> result = new HashSet<>();
|
||||
JsonArray rolesArr = array.getAsJsonArray();
|
||||
for (JsonElement role : rolesArr) {
|
||||
result.add(role.getAsString().trim());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class PrivilegeElementToJsonVisitor implements PrivilegeElementVisitor<Js
|
|||
jsonObject.addProperty("name", roleRep.getName());
|
||||
|
||||
JsonArray privilegesJ = new JsonArray();
|
||||
roleRep.getPrivileges().forEach(p -> privilegesJ.add(p.accept(this)));
|
||||
roleRep.getPrivileges().values().forEach(p -> privilegesJ.add(p.accept(this)));
|
||||
jsonObject.add("privileges", privilegesJ);
|
||||
|
||||
return jsonObject;
|
||||
|
|
|
@ -1,46 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege"/>
|
||||
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/>
|
||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
|
||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -1,40 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
||||
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
|
@ -42,5 +23,4 @@
|
|||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -14,6 +14,7 @@ public class PrivilegeConstants {
|
|||
public static final String PRIMARY_LOCATION = "primaryLocation";
|
||||
public static final String SECONDARY_LOCATIONS = "secondaryLocations";
|
||||
public static final String ROLES = "roles";
|
||||
public static final String GROUPS = "groups";
|
||||
public static final String EMAIL = "email";
|
||||
|
||||
public static final String ROLE_STROLCH_ADMIN = "StrolchAdmin";
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
package li.strolch.privilege.handler;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.model.UserState;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.helper.ExceptionHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.*;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
|
@ -10,21 +20,20 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.model.UserState;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(BaseLdapPrivilegeHandler.class);
|
||||
public static final String LDAP_FILTER_TEMPLATE = "(&(objectCategory=person)(objectClass=user)(%s=%s)%s)";
|
||||
public static final String SAM_ACCOUNT_NAME = "sAMAccountName";
|
||||
public static final String USER_PRINCIPAL_NAME = "userPrincipalName";
|
||||
|
||||
private String providerUrl;
|
||||
private String searchBase;
|
||||
private String additionalFilter;
|
||||
private String domain;
|
||||
private String domainPrefix;
|
||||
|
||||
@Override
|
||||
public void initialize(ScheduledExecutorService executorService, Map<String, String> parameterMap,
|
||||
|
@ -36,9 +45,24 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
userChallengeHandler, ssoHandler, policyMap);
|
||||
|
||||
this.providerUrl = parameterMap.get("providerUrl");
|
||||
logger.info("providerUrl: " + this.providerUrl);
|
||||
this.searchBase = parameterMap.get("searchBase");
|
||||
this.domain = parameterMap.get("domain");
|
||||
logger.info("searchBase: " + this.searchBase);
|
||||
this.additionalFilter = trimOrEmpty(parameterMap.get("additionalFilter"));
|
||||
if (!this.additionalFilter.isEmpty())
|
||||
logger.info("additionalFilter: " + this.additionalFilter);
|
||||
this.domain = trimOrEmpty(parameterMap.get("domain"));
|
||||
if (!this.domain.isEmpty()) {
|
||||
if (this.domain.startsWith("@")) {
|
||||
logger.warn(
|
||||
"Remove the @ symbol from the domain property! Will be added automatically where required.");
|
||||
this.domain = this.domain.substring(1);
|
||||
}
|
||||
this.domainPrefix = this.domain + '\\';
|
||||
|
||||
logger.info("domain: " + this.domain);
|
||||
logger.info("domain prefix: " + this.domainPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,52 +73,24 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
if (internalUser != null && internalUser.getUserState() != UserState.REMOTE)
|
||||
return super.checkCredentialsAndUserState(username, password);
|
||||
|
||||
// Set up the environment for creating the initial context
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
String userPrincipalName;
|
||||
if (this.domain.isEmpty()) {
|
||||
userPrincipalName = username;
|
||||
} else {
|
||||
if (!this.domainPrefix.isEmpty() && username.startsWith(this.domainPrefix)) {
|
||||
logger.warn("Trimming domain from given username, to first search in sAMAccountName");
|
||||
username = username.substring(this.domainPrefix.length());
|
||||
}
|
||||
userPrincipalName = username + "@" + this.domain;
|
||||
}
|
||||
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, this.providerUrl);
|
||||
|
||||
// Authenticate
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.put(Context.SECURITY_PRINCIPAL, username + this.domain);
|
||||
env.put(Context.SECURITY_CREDENTIALS, new String(password));
|
||||
|
||||
logger.info("User {} tries to login on ldap {}", username + this.domain, this.providerUrl);
|
||||
logger.info("User {} tries to login on ldap {}", username, this.providerUrl);
|
||||
|
||||
// Create the initial context
|
||||
DirContext ctx = null;
|
||||
try {
|
||||
ctx = new InitialDirContext(env);
|
||||
|
||||
//Create the search controls
|
||||
SearchControls searchCtls = new SearchControls();
|
||||
|
||||
//Specify the search scope
|
||||
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
|
||||
String searchFilter = "(&(objectCategory=person)(objectClass=user)(userPrincipalName=" + username +
|
||||
this.domain + "))";
|
||||
|
||||
// Search for objects using the filter
|
||||
NamingEnumeration<SearchResult> answer = ctx.search(this.searchBase, searchFilter, searchCtls);
|
||||
|
||||
if (!answer.hasMore()) {
|
||||
|
||||
logger.warn("No LDAP data retrieved using userPrincipalName, trying with sAMAccountName...");
|
||||
searchFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=" + username + "))";
|
||||
answer = ctx.search(this.searchBase, searchFilter, searchCtls);
|
||||
|
||||
if (!answer.hasMore())
|
||||
throw new AccessDeniedException("Could not login with user: " + username + this.domain +
|
||||
" on Ldap: no LDAP Data, for either userPrincipalName or sAMAccountName");
|
||||
}
|
||||
|
||||
SearchResult searchResult = answer.next();
|
||||
if (answer.hasMore())
|
||||
throw new AccessDeniedException(
|
||||
"Could not login with user: " + username + this.domain + " on Ldap: Multiple LDAP Data");
|
||||
|
||||
ctx = new InitialDirContext(buildLdapEnv(password, userPrincipalName));
|
||||
SearchResult searchResult = searchLdap(username, ctx, userPrincipalName);
|
||||
User user = buildUserFromSearchResult(username, searchResult);
|
||||
|
||||
// persist this user
|
||||
|
@ -104,13 +100,15 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
this.persistenceHandler.replaceUser(user);
|
||||
|
||||
if (this.autoPersistOnUserChangesData)
|
||||
this.persistenceHandler.persist();
|
||||
persistModelAsync();
|
||||
|
||||
return user;
|
||||
|
||||
} catch (AccessDeniedException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.error("Could not login with user: " + username + this.domain + " on Ldap", e);
|
||||
throw new AccessDeniedException("Could not login with user: " + username + this.domain + " on Ldap", e);
|
||||
logger.error("Could not login with user: " + username + " on Ldap", e);
|
||||
throw new AccessDeniedException("Could not login with user: " + username + " on Ldap", e);
|
||||
} finally {
|
||||
if (ctx != null) {
|
||||
try {
|
||||
|
@ -122,6 +120,65 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private Hashtable<String, String> buildLdapEnv(char[] password, String userPrincipalName) {
|
||||
|
||||
// Set up the environment for creating the initial context
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, this.providerUrl);
|
||||
|
||||
// Authenticate
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.put(Context.SECURITY_PRINCIPAL, userPrincipalName);
|
||||
env.put(Context.SECURITY_CREDENTIALS, new String(password));
|
||||
env.put(Context.REFERRAL, "ignore");
|
||||
return env;
|
||||
}
|
||||
|
||||
private SearchResult searchLdap(String username, DirContext ctx, String userPrincipalName) throws NamingException {
|
||||
SearchControls searchControls = new SearchControls();
|
||||
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
|
||||
// the first search is using sAMAccountName
|
||||
NamingEnumeration<SearchResult> answer = ctx.search(this.searchBase,
|
||||
LDAP_FILTER_TEMPLATE.formatted(SAM_ACCOUNT_NAME, username, this.additionalFilter), searchControls);
|
||||
|
||||
SearchResult searchResult = null;
|
||||
while (searchResult == null) {
|
||||
try {
|
||||
|
||||
// and if we don't find anything, then we search with userPrincipalName
|
||||
if (!answer.hasMore()) {
|
||||
|
||||
logger.warn("No LDAP data retrieved using " + SAM_ACCOUNT_NAME + ", trying with " +
|
||||
USER_PRINCIPAL_NAME + "...");
|
||||
answer = ctx.search(this.searchBase,
|
||||
LDAP_FILTER_TEMPLATE.formatted(USER_PRINCIPAL_NAME, userPrincipalName,
|
||||
this.additionalFilter), searchControls);
|
||||
|
||||
if (!answer.hasMore())
|
||||
throw new AccessDeniedException("Could not login user: " + username +
|
||||
" on Ldap: no LDAP Data, for either sAMAccountName or userPrincipalName searches. Domain used is " +
|
||||
this.domain);
|
||||
}
|
||||
|
||||
searchResult = answer.next();
|
||||
if (answer.hasMore())
|
||||
throw new AccessDeniedException(
|
||||
"Could not login with user: " + username + " on Ldap: Multiple LDAP Data");
|
||||
|
||||
} catch (PartialResultException e) {
|
||||
if (ExceptionHelper.getExceptionMessage(e).contains("Unprocessed Continuation Reference(s)"))
|
||||
logger.warn("Ignoring partial result exception, as we are not following referrals!");
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
protected User buildUserFromSearchResult(String username, SearchResult sr) throws Exception {
|
||||
Attributes attrs = sr.getAttributes();
|
||||
|
||||
|
@ -135,19 +192,20 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
Set<String> ldapGroups = getLdapGroups(username, attrs);
|
||||
logger.info("User " + username + " is member of the following LDAP groups: ");
|
||||
ldapGroups.forEach(s -> logger.info("- " + s));
|
||||
Set<String> strolchGroups = mapToStrolchGroups(username, ldapGroups);
|
||||
Set<String> strolchRoles = mapToStrolchRoles(username, ldapGroups);
|
||||
|
||||
Map<String, String> properties = buildProperties(username, attrs, ldapGroups, strolchRoles);
|
||||
|
||||
return new User(username, username, null, firstName, lastName, UserState.REMOTE, strolchRoles, locale,
|
||||
properties, false, new UserHistory());
|
||||
return new User(username, username, null, firstName, lastName, UserState.REMOTE, strolchGroups, strolchRoles,
|
||||
locale, properties, false, UserHistory.EMPTY);
|
||||
}
|
||||
|
||||
protected abstract Map<String, String> buildProperties(String username, Attributes attrs, Set<String> ldapGroups,
|
||||
Set<String> strolchRoles) throws Exception;
|
||||
|
||||
protected String validateLdapUsername(String username, Attributes attrs) throws NamingException {
|
||||
Attribute sAMAccountName = attrs.get("sAMAccountName");
|
||||
Attribute sAMAccountName = attrs.get(SAM_ACCOUNT_NAME);
|
||||
if (sAMAccountName == null || !username.equalsIgnoreCase(sAMAccountName.get().toString()))
|
||||
throw new AccessDeniedException(
|
||||
"Could not login with user: " + username + this.domain + " on Ldap: Wrong LDAP Data");
|
||||
|
@ -168,5 +226,7 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
|||
|
||||
protected abstract Set<String> getLdapGroups(String username, Attributes attrs) throws NamingException;
|
||||
|
||||
protected abstract Set<String> mapToStrolchGroups(String username, Set<String> ldapGroups);
|
||||
|
||||
protected abstract Set<String> mapToStrolchRoles(String username, Set<String> ldapGroups);
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ public class BasicPasswordStrengthHandler implements PasswordStrengthHandler {
|
|||
String description;
|
||||
|
||||
if (this.maxLength < 100)
|
||||
description = MessageFormat
|
||||
.format(getString(locale, "Privilege.passwordLengthBetween"), this.minLength, this.maxLength);
|
||||
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthBetween"), this.minLength,
|
||||
this.maxLength);
|
||||
else
|
||||
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthAtLeast"), this.minLength);
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ import static li.strolch.privilege.helper.XmlConstants.*;
|
|||
* <p>
|
||||
* Required parameters:
|
||||
* <ul>
|
||||
* <li>{@link XmlConstants#XML_PARAM_HASH_ALGORITHM}</li>
|
||||
* <li>{@link XmlConstants#PARAM_HASH_ALGORITHM}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -121,7 +121,7 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
|||
try {
|
||||
|
||||
MessageDigest digest = MessageDigest.getInstance(this.nonSaltAlgorithm);
|
||||
return new PasswordCrypt(digest.digest(new String(password).getBytes()), null);
|
||||
return PasswordCrypt.of(digest.digest(new String(password).getBytes()), null);
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new PrivilegeException(MessageFormat.format("Algorithm {0} was not found!", nonSaltAlgorithm),
|
||||
|
@ -151,9 +151,8 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
|||
|
||||
@Override
|
||||
public boolean isPasswordCryptOutdated(PasswordCrypt passwordCrypt) {
|
||||
return passwordCrypt.getSalt() == null || passwordCrypt.getHashAlgorithm() == null ||
|
||||
passwordCrypt.getHashIterations() != this.iterations ||
|
||||
passwordCrypt.getHashKeyLength() != this.keyLength;
|
||||
return passwordCrypt.salt() == null || passwordCrypt.hashAlgorithm() == null ||
|
||||
passwordCrypt.hashIterations() != this.iterations || passwordCrypt.hashKeyLength() != this.keyLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -163,13 +162,13 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
|||
this.secureRandom = new SecureRandom();
|
||||
|
||||
// get hash algorithm parameters
|
||||
this.algorithm = parameterMap.getOrDefault(XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||
this.nonSaltAlgorithm = parameterMap.getOrDefault(XML_PARAM_HASH_ALGORITHM_NON_SALT,
|
||||
this.algorithm = parameterMap.getOrDefault(PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||
this.nonSaltAlgorithm = parameterMap.getOrDefault(PARAM_HASH_ALGORITHM_NON_SALT,
|
||||
DEFAULT_ALGORITHM_NON_SALT);
|
||||
this.iterations = Integer.parseInt(
|
||||
parameterMap.getOrDefault(XML_PARAM_HASH_ITERATIONS, valueOf(DEFAULT_ITERATIONS)));
|
||||
parameterMap.getOrDefault(PARAM_HASH_ITERATIONS, valueOf(DEFAULT_ITERATIONS)));
|
||||
this.keyLength = Integer.parseInt(
|
||||
parameterMap.getOrDefault(XML_PARAM_HASH_KEY_LENGTH, valueOf(DEFAULT_KEY_LENGTH)));
|
||||
parameterMap.getOrDefault(PARAM_HASH_KEY_LENGTH, valueOf(DEFAULT_KEY_LENGTH)));
|
||||
|
||||
// test non-salt hash algorithm
|
||||
try {
|
||||
|
@ -178,7 +177,7 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
|||
MessageFormat.format("Using non-salt hashing algorithm {0}", this.nonSaltAlgorithm));
|
||||
} catch (Exception e) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}";
|
||||
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XML_PARAM_HASH_ALGORITHM_NON_SALT,
|
||||
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), PARAM_HASH_ALGORITHM_NON_SALT,
|
||||
e.getLocalizedMessage());
|
||||
throw new PrivilegeException(msg, e);
|
||||
}
|
||||
|
@ -189,7 +188,7 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
|||
DefaultEncryptionHandler.logger.info(MessageFormat.format("Using hashing algorithm {0}", this.algorithm));
|
||||
} catch (Exception e) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}";
|
||||
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XML_PARAM_HASH_ALGORITHM,
|
||||
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), PARAM_HASH_ALGORITHM,
|
||||
e.getLocalizedMessage());
|
||||
throw new PrivilegeException(msg, e);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,11 @@
|
|||
package li.strolch.privilege.handler;
|
||||
|
||||
import static java.lang.String.join;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import li.strolch.privilege.helper.LdapHelper;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
|
@ -13,12 +14,11 @@ import java.io.FileReader;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import li.strolch.privilege.helper.LdapHelper;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import static java.lang.String.join;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||
|
||||
public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||
|
||||
|
@ -42,15 +42,14 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
|||
DBC.PRE.assertNotEmpty("realm must be set!", realm);
|
||||
|
||||
this.defaultLocale = parameterMap.containsKey("defaultLocale") ?
|
||||
Locale.forLanguageTag(parameterMap.get("defaultLocale")) :
|
||||
Locale.getDefault();
|
||||
Locale.forLanguageTag(parameterMap.get("defaultLocale")) : Locale.getDefault();
|
||||
|
||||
String configFileS = parameterMap.get("configFile");
|
||||
DBC.PRE.assertNotEmpty("configFile param must be set!", configFileS);
|
||||
File configFile = new File(configFileS);
|
||||
if (!configFile.exists() || !configFile.isFile() || !configFile.canRead())
|
||||
throw new IllegalStateException("configFile does not exist, is not a file, or can not be read at path "
|
||||
+ configFile.getAbsolutePath());
|
||||
throw new IllegalStateException("configFile does not exist, is not a file, or can not be read at path " +
|
||||
configFile.getAbsolutePath());
|
||||
|
||||
// parse the configuration file
|
||||
JsonObject configJ;
|
||||
|
@ -82,14 +81,14 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
|||
// validate the configuration
|
||||
for (String name : this.ldapGroupNames) {
|
||||
JsonObject config = ldapGroupConfigs.get(name).getAsJsonObject();
|
||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray()
|
||||
|| config.get(LOCATION).getAsJsonArray().size() == 0)
|
||||
throw new IllegalStateException("LDAP Group " + name
|
||||
+ " is missing a location attribute, or it is not an array or the array is empty");
|
||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray()
|
||||
|| config.get(LOCATION).getAsJsonArray().size() == 0)
|
||||
throw new IllegalStateException("LDAP Group " + name
|
||||
+ " is missing a roles attribute, or it is not an array or the array is empty");
|
||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray() ||
|
||||
config.get(LOCATION).getAsJsonArray().isEmpty())
|
||||
throw new IllegalStateException("LDAP Group " + name +
|
||||
" is missing a location attribute, or it is not an array or the array is empty");
|
||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray() ||
|
||||
config.get(LOCATION).getAsJsonArray().isEmpty())
|
||||
throw new IllegalStateException("LDAP Group " + name +
|
||||
" is missing a roles attribute, or it is not an array or the array is empty");
|
||||
}
|
||||
|
||||
this.userLdapGroupOverrides = new HashMap<>();
|
||||
|
@ -133,33 +132,40 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
|||
logger.info("Overriding LDAP group for user " + username + " to " + overrideGroup);
|
||||
}
|
||||
|
||||
Set<String> relevantLdapGroups = ldapGroups.stream()
|
||||
.filter(s -> this.ldapGroupNames.contains(s))
|
||||
Set<String> relevantLdapGroups = ldapGroups.stream().filter(s -> this.ldapGroupNames.contains(s))
|
||||
.collect(toSet());
|
||||
if (relevantLdapGroups.isEmpty())
|
||||
throw new IllegalStateException("User " + username
|
||||
+ " can not login, as none of their LDAP Groups have mappings to Strolch Roles!");
|
||||
throw new IllegalStateException("User " + username +
|
||||
" can not login, as none of their LDAP Groups have mappings to Strolch Roles!");
|
||||
|
||||
if (relevantLdapGroups.size() > 1) {
|
||||
logger.warn(
|
||||
"User " + username + " has multiple relevant LDAP Groups which will lead to undefined behaviour: "
|
||||
+ join(",", relevantLdapGroups));
|
||||
"User " + username + " has multiple relevant LDAP Groups which will lead to undefined behaviour: " +
|
||||
join(",", relevantLdapGroups));
|
||||
}
|
||||
|
||||
return relevantLdapGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> mapToStrolchGroups(String username, Set<String> ldapGroups) {
|
||||
return mapLdapGroupToStrolch(ldapGroups, GROUPS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> mapToStrolchRoles(String username, Set<String> ldapGroups) {
|
||||
return mapLdapGroupToStrolch(ldapGroups, ROLES);
|
||||
}
|
||||
|
||||
Set<String> strolchRoles = new HashSet<>();
|
||||
|
||||
private Set<String> mapLdapGroupToStrolch(Set<String> ldapGroups, String type) {
|
||||
Set<String> mappedValues = new HashSet<>();
|
||||
for (String relevantLdapGroup : ldapGroups) {
|
||||
JsonObject mappingJ = this.ldapGroupConfigs.get(relevantLdapGroup).getAsJsonObject();
|
||||
mappingJ.get(ROLES).getAsJsonArray().forEach(e -> strolchRoles.add(e.getAsString()));
|
||||
if (mappingJ.has(type))
|
||||
mappingJ.get(type).getAsJsonArray().forEach(e -> mappedValues.add(e.getAsString()));
|
||||
}
|
||||
|
||||
return strolchRoles;
|
||||
return mappedValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -194,9 +200,8 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
|||
} else {
|
||||
String location = primaryLocationJ.getAsString();
|
||||
if (!secondaryLocations.contains(location)) {
|
||||
logger.warn(
|
||||
"Primary location already set by previous LDAP Group config for LDAP Group " + ldapGroup
|
||||
+ ", adding to secondary locations.");
|
||||
logger.warn("Primary location already set by previous LDAP Group config for LDAP Group " +
|
||||
ldapGroup + ", adding to secondary locations.");
|
||||
secondaryLocations.add(location);
|
||||
}
|
||||
}
|
||||
|
@ -210,9 +215,8 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
|||
else
|
||||
secondaryLocationsJ.getAsJsonArray().forEach(s -> secondaryLocations.add(s.getAsString()));
|
||||
} else {
|
||||
logger.warn(
|
||||
"Secondary locations already set by previous LDAP Group config for LDAP Group " + ldapGroup
|
||||
+ ", adding additional");
|
||||
logger.warn("Secondary locations already set by previous LDAP Group config for LDAP Group " +
|
||||
ldapGroup + ", adding additional");
|
||||
if (secondaryLocationsJ.isJsonPrimitive())
|
||||
secondaryLocations.add(secondaryLocationsJ.getAsString());
|
||||
else
|
||||
|
|
|
@ -16,9 +16,9 @@ public class MailUserChallengeHandler extends UserChallengeHandler {
|
|||
|
||||
String subject = "Mail TAN";
|
||||
|
||||
String text = "Hello " + user.getFirstname() + " " + user.getLastname() + "\n\n"
|
||||
+ "You have requested an action which requires you to respond to a challenge.\n\n"
|
||||
+ "Please use the following code to response to the challenge:\n\n" + challenge;
|
||||
String text = "Hello " + user.getFirstname() + " " + user.getLastname() + "\n\n" +
|
||||
"You have requested an action which requires you to respond to a challenge.\n\n" +
|
||||
"Please use the following code to response to the challenge:\n\n" + challenge;
|
||||
String recipient = user.getEmail();
|
||||
if (StringHelper.isEmpty(recipient)) {
|
||||
String msg = "User {0} has no property {1}, so can not initiate challenge!";
|
||||
|
|
|
@ -12,8 +12,7 @@ public interface PasswordStrengthHandler {
|
|||
* Initialize the concrete {@link PasswordStrengthHandler}. The passed parameter map contains any configuration the
|
||||
* concrete {@link PasswordStrengthHandler} might need
|
||||
*
|
||||
* @param parameterMap
|
||||
* a map containing configuration properties
|
||||
* @param parameterMap a map containing configuration properties
|
||||
*/
|
||||
void initialize(Map<String, String> parameterMap);
|
||||
|
||||
|
@ -21,16 +20,16 @@ public interface PasswordStrengthHandler {
|
|||
* Returns a description what a password must contain in order to be regarded as strong for this concrete
|
||||
* implementation
|
||||
*
|
||||
* @param locale the locale in which to return the description
|
||||
*
|
||||
* @return a description of a strong password
|
||||
* @param locale
|
||||
*/
|
||||
String getDescription(Locale locale);
|
||||
|
||||
/**
|
||||
* Performs the validation of the given password
|
||||
*
|
||||
* @param password
|
||||
* the password to validate
|
||||
* @param password the password to validate
|
||||
*
|
||||
* @return true if the password meets the criteria for a strong password
|
||||
*/
|
||||
|
|
|
@ -15,15 +15,18 @@
|
|||
*/
|
||||
package li.strolch.privilege.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The {@link PersistenceHandler} takes care of retrieving and persisting model objects to the underlying database. This
|
||||
|
@ -33,7 +36,7 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
|||
* <p>
|
||||
* The {@link PersistenceHandler} also serves the special {@link PrivilegePolicy} objects. These policies are special
|
||||
* objects which implement an algorithm to define if an action is allowed on a {@link Restrictable} by a {@link Role}
|
||||
* and {@link IPrivilege}
|
||||
* and {@link Privilege}
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -47,6 +50,13 @@ public interface PersistenceHandler {
|
|||
*/
|
||||
List<User> getAllUsers();
|
||||
|
||||
/**
|
||||
* Returns all currently known {@link Group}s
|
||||
*
|
||||
* @return all currently known {@link Group}s
|
||||
*/
|
||||
List<Group> getAllGroups();
|
||||
|
||||
/**
|
||||
* Returns all currently known {@link Role}s
|
||||
*
|
||||
|
@ -57,18 +67,25 @@ public interface PersistenceHandler {
|
|||
/**
|
||||
* Returns a {@link User} object from the underlying database
|
||||
*
|
||||
* @param username
|
||||
* the name/id of the {@link User} object to return
|
||||
* @param username the name/id of the {@link User} object to return
|
||||
*
|
||||
* @return the {@link User} object, or null if it was not found
|
||||
*/
|
||||
User getUser(String username);
|
||||
|
||||
/**
|
||||
* Returns a {@link Group} object from the underlying database
|
||||
*
|
||||
* @param groupName the name/id of the {@link Group} object to return
|
||||
*
|
||||
* @return the {@link Group} object, or null if it was not found
|
||||
*/
|
||||
Group getGroup(String groupName);
|
||||
|
||||
/**
|
||||
* Returns a {@link Role} object from the underlying database
|
||||
*
|
||||
* @param roleName
|
||||
* the name/id of the {@link Role} object to return
|
||||
* @param roleName the name/id of the {@link Role} object to return
|
||||
*
|
||||
* @return the {@link Role} object, or null if it was not found
|
||||
*/
|
||||
|
@ -77,18 +94,25 @@ public interface PersistenceHandler {
|
|||
/**
|
||||
* Removes a {@link User} with the given name and returns the removed object if it existed
|
||||
*
|
||||
* @param username
|
||||
* the name of the {@link User} to remove
|
||||
* @param username the name of the {@link User} to remove
|
||||
*
|
||||
* @return the {@link User} removed, or null if it did not exist
|
||||
*/
|
||||
User removeUser(String username);
|
||||
|
||||
/**
|
||||
* Removes a {@link Group} with the given name and returns the removed object if it existed
|
||||
*
|
||||
* @param groupName the name of the {@link Group} to remove
|
||||
*
|
||||
* @return the {@link Group} removed, or null if it did not exist
|
||||
*/
|
||||
Group removeGroup(String groupName);
|
||||
|
||||
/**
|
||||
* Removes a {@link Role} with the given name and returns the removed object if it existed
|
||||
*
|
||||
* @param roleName
|
||||
* the name of the {@link Role} to remove
|
||||
* @param roleName the name of the {@link Role} to remove
|
||||
*
|
||||
* @return the {@link Role} removed, or null if it did not exist
|
||||
*/
|
||||
|
@ -97,41 +121,51 @@ public interface PersistenceHandler {
|
|||
/**
|
||||
* Adds a {@link User} object to the underlying database
|
||||
*
|
||||
* @param user
|
||||
* the {@link User} object to add
|
||||
* @param user the {@link User} object to add
|
||||
*/
|
||||
void addUser(User user);
|
||||
|
||||
/**
|
||||
* Replaces the existing {@link User} object in the underlying database
|
||||
*
|
||||
* @param user
|
||||
* the {@link User} object to add
|
||||
* @param user the {@link User} object to add
|
||||
*/
|
||||
void replaceUser(User user);
|
||||
|
||||
/**
|
||||
* Adds a {@link Role} object to the underlying database
|
||||
*
|
||||
* @param role
|
||||
* the {@link User} object to add
|
||||
* @param role the {@link Role} object to add
|
||||
*/
|
||||
void addRole(Role role);
|
||||
|
||||
/**
|
||||
* Replaces the {@link Role} object in the underlying database
|
||||
*
|
||||
* @param role
|
||||
* the {@link User} object to add
|
||||
* @param role the {@link User} object to add
|
||||
*/
|
||||
void replaceRole(Role role);
|
||||
|
||||
/**
|
||||
* Adds a {@link Group} object to the underlying database
|
||||
*
|
||||
* @param group the {@link Group} object to add
|
||||
*/
|
||||
void addGroup(Group group);
|
||||
|
||||
/**
|
||||
* Replaces the {@link Group} object in the underlying database
|
||||
*
|
||||
* @param group the {@link Group} object to add
|
||||
*/
|
||||
void replaceGroup(Group group);
|
||||
|
||||
/**
|
||||
* Informs this {@link PersistenceHandler} to persist any changes which need to be saved
|
||||
*
|
||||
* @return true if changes were persisted successfully, false if nothing needed to be persisted
|
||||
*/
|
||||
boolean persist();
|
||||
boolean persist() throws XMLStreamException, IOException;
|
||||
|
||||
/**
|
||||
* Informs this {@link PersistenceHandler} to reload the data from the backend
|
||||
|
@ -144,8 +178,7 @@ public interface PersistenceHandler {
|
|||
* Initialize the concrete {@link PersistenceHandler}. The passed parameter map contains any configuration the
|
||||
* concrete {@link PersistenceHandler} might need
|
||||
*
|
||||
* @param parameterMap
|
||||
* a map containing configuration properties
|
||||
* @param parameterMap a map containing configuration properties
|
||||
*/
|
||||
void initialize(Map<String, String> parameterMap);
|
||||
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
package li.strolch.privilege.handler;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConflictResolution;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.base.PrivilegeModelException;
|
||||
import li.strolch.privilege.model.*;
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static li.strolch.privilege.handler.DefaultPrivilegeHandler.streamAllRolesForUser;
|
||||
|
||||
public class PrivilegeContextBuilder {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PrivilegeContextBuilder.class);
|
||||
|
||||
private final Map<String, Class<PrivilegePolicy>> policyMap;
|
||||
private final DefaultPrivilegeHandler privilegeHandler;
|
||||
private final PrivilegeConflictResolution conflictResolution;
|
||||
private final PersistenceHandler persistenceHandler;
|
||||
|
||||
private Set<String> userGroups;
|
||||
private Set<String> userRoles;
|
||||
private Map<String, String> userProperties;
|
||||
|
||||
public PrivilegeContextBuilder(DefaultPrivilegeHandler privilegeHandler) {
|
||||
this.privilegeHandler = privilegeHandler;
|
||||
this.persistenceHandler = privilegeHandler.persistenceHandler;
|
||||
this.policyMap = privilegeHandler.policyMap;
|
||||
this.conflictResolution = privilegeHandler.privilegeConflictResolution;
|
||||
}
|
||||
|
||||
public PrivilegeContext buildPrivilegeContext(Usage usage, User user, String source, ZonedDateTime loginTime,
|
||||
boolean keepAlive) {
|
||||
String authToken = this.privilegeHandler.getEncryptionHandler().nextToken();
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
return buildPrivilegeContext(usage, user, authToken, sessionId, source, loginTime, keepAlive);
|
||||
}
|
||||
|
||||
public PrivilegeContext buildPrivilegeContext(Usage usage, User user, String authToken, String sessionId,
|
||||
String source, ZonedDateTime loginTime, boolean keepAlive) {
|
||||
DBC.PRE.assertNotEmpty("source must not be empty!", source);
|
||||
|
||||
keepAlive = keepAlive && this.privilegeHandler.allowSessionRefresh;
|
||||
|
||||
prepare(user);
|
||||
|
||||
Map<String, Privilege> privileges = new HashMap<>();
|
||||
Map<String, PrivilegePolicy> policies = new HashMap<>();
|
||||
|
||||
// cache the privileges and policies for this user by role
|
||||
addPrivilegesForRoles(this.userRoles, user.getUsername(), privileges, policies);
|
||||
|
||||
UserRep userRep = user.asUserRep();
|
||||
userRep.setRoles(this.userRoles);
|
||||
userRep.setGroups(this.userGroups);
|
||||
userRep.setProperties(this.userProperties);
|
||||
userRep.readOnly();
|
||||
|
||||
Certificate certificate = new Certificate(usage, sessionId, user.getUsername(), user.getFirstname(),
|
||||
user.getLastname(), user.getUserState(), authToken, source, loginTime, keepAlive, user.getLocale(),
|
||||
this.userGroups, this.userRoles, this.userProperties);
|
||||
|
||||
return new PrivilegeContext(userRep, certificate, privileges, policies);
|
||||
}
|
||||
|
||||
private void prepare(User user) {
|
||||
this.userGroups = user.getGroups().stream().sorted().collect(toCollection(TreeSet::new));
|
||||
this.userRoles = streamAllRolesForUser(this.persistenceHandler, user).sorted()
|
||||
.collect(toCollection(TreeSet::new));
|
||||
this.userProperties = new HashMap<>(user.getProperties());
|
||||
|
||||
// copy properties from groups to user properties
|
||||
for (String groupName : this.userGroups) {
|
||||
Group group = this.persistenceHandler.getGroup(groupName);
|
||||
if (group == null) {
|
||||
logger.error("Group " + groupName + " does not exist!");
|
||||
continue;
|
||||
}
|
||||
Map<String, String> groupProperties = group.getProperties();
|
||||
for (String key : groupProperties.keySet()) {
|
||||
String replaced = this.userProperties.put(key, groupProperties.get(key));
|
||||
if (replaced != null)
|
||||
logger.error("Duplicate property {} for user {} from group {}", key, user.getUsername(), groupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPrivilegesForRoles(Set<String> roles, String userName, Map<String, Privilege> privileges,
|
||||
Map<String, PrivilegePolicy> policies) {
|
||||
|
||||
for (String roleName : roles) {
|
||||
Role role = this.persistenceHandler.getRole(roleName);
|
||||
if (role == null) {
|
||||
logger.error("Role " + roleName + " does not exist for user " + userName);
|
||||
} else {
|
||||
addPrivilegesForRole(userName, role, privileges, policies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPrivilegesForRole(String userName, Role role, Map<String, Privilege> privileges,
|
||||
Map<String, PrivilegePolicy> policies) {
|
||||
|
||||
for (Privilege privilege : role.privilegeMap().values()) {
|
||||
String privilegeName = privilege.name();
|
||||
|
||||
if (!privileges.containsKey(privilegeName)) {
|
||||
privileges.put(privilegeName, privilege);
|
||||
} else {
|
||||
handleDuplicatePrivilege(userName, role, privileges, privilege, privilegeName);
|
||||
}
|
||||
|
||||
// cache the policy for the privilege
|
||||
addPolicyForPrivilege(policies, privilege, privilegeName);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPolicyForPrivilege(Map<String, PrivilegePolicy> policies, Privilege privilege,
|
||||
String privilegeName) {
|
||||
String policyName = privilege.getPolicy();
|
||||
if (policies.containsKey(policyName))
|
||||
return;
|
||||
|
||||
PrivilegePolicy policy = getPolicy(policyName);
|
||||
if (policy == null) {
|
||||
logger.error(format("The Policy {0} does not exist for Privilege {1}", policyName, privilegeName));
|
||||
} else {
|
||||
policies.put(policyName, policy);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDuplicatePrivilege(String userName, Role role, Map<String, Privilege> privileges,
|
||||
Privilege additionalPrivilege, String privilegeName) {
|
||||
|
||||
// for strict, we have to throw an exception
|
||||
if (this.conflictResolution.isStrict())
|
||||
throw new PrivilegeModelException(
|
||||
format("User " + userName + " has conflicts for privilege {0} with role {1}", privilegeName,
|
||||
role.name()));
|
||||
|
||||
// merge privileges
|
||||
Privilege knownPrivilege = privileges.get(privilegeName);
|
||||
boolean allAllowed = knownPrivilege.isAllAllowed() || additionalPrivilege.isAllAllowed();
|
||||
Set<String> allowList;
|
||||
Set<String> denyList;
|
||||
if (allAllowed) {
|
||||
allowList = Set.of();
|
||||
denyList = Set.of();
|
||||
} else {
|
||||
allowList = new HashSet<>(knownPrivilege.getAllowList());
|
||||
allowList.addAll(additionalPrivilege.getAllowList());
|
||||
denyList = new HashSet<>(knownPrivilege.getDenyList());
|
||||
denyList.addAll(additionalPrivilege.getDenyList());
|
||||
}
|
||||
|
||||
String policy = knownPrivilege.getPolicy();
|
||||
privileges.put(privilegeName, new Privilege(knownPrivilege.getName(), policy, allAllowed, denyList, allowList));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This method instantiates a {@link PrivilegePolicy} object from the given policyName. The {@link PrivilegePolicy}
|
||||
* is not stored in a database. The privilege name is a class name and is then used to instantiate a new
|
||||
* {@link PrivilegePolicy} object
|
||||
* </p>
|
||||
*
|
||||
* @param policyName the class name of the {@link PrivilegePolicy} object to return
|
||||
*
|
||||
* @return the {@link PrivilegePolicy} object
|
||||
*
|
||||
* @throws PrivilegeException if the {@link PrivilegePolicy} object for the given policy name could not be
|
||||
* instantiated
|
||||
*/
|
||||
private PrivilegePolicy getPolicy(String policyName) {
|
||||
|
||||
// get the policies class
|
||||
Class<PrivilegePolicy> policyClazz = this.policyMap.get(policyName);
|
||||
if (policyClazz == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// instantiate the policy
|
||||
PrivilegePolicy policy;
|
||||
try {
|
||||
|
||||
policy = policyClazz.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
String msg = "The class for the policy with the name {0} does not exist!{1}";
|
||||
msg = format(msg, policyName, policyName);
|
||||
throw new PrivilegeModelException(msg, e);
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,864 @@
|
|||
package li.strolch.privilege.handler;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConflictResolution;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.base.PrivilegeModelException;
|
||||
import li.strolch.privilege.model.*;
|
||||
import li.strolch.privilege.model.internal.PasswordCrypt;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.collections.Tuple;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static li.strolch.utils.helper.StringHelper.*;
|
||||
|
||||
public class PrivilegeCrudHandler {
|
||||
|
||||
private final DefaultPrivilegeHandler privilegeHandler;
|
||||
private final PersistenceHandler persistenceHandler;
|
||||
private final Map<String, Class<PrivilegePolicy>> policyMap;
|
||||
private final PrivilegeConflictResolution privilegeConflictResolution;
|
||||
|
||||
public PrivilegeCrudHandler(DefaultPrivilegeHandler privilegeHandler, Map<String, Class<PrivilegePolicy>> policyMap,
|
||||
PrivilegeConflictResolution privilegeConflictResolution) {
|
||||
this.privilegeHandler = privilegeHandler;
|
||||
this.persistenceHandler = privilegeHandler.persistenceHandler;
|
||||
this.policyMap = policyMap;
|
||||
this.privilegeConflictResolution = privilegeConflictResolution;
|
||||
}
|
||||
|
||||
public RoleRep getRole(Certificate certificate, String roleName) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_GET_ROLE);
|
||||
|
||||
Role role = this.persistenceHandler.getRole(roleName);
|
||||
if (role == null)
|
||||
return null;
|
||||
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_GET_ROLE, new Tuple(null, role)));
|
||||
|
||||
return role.asRoleRep();
|
||||
}
|
||||
|
||||
public UserRep getUser(Certificate certificate, String username) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_GET_USER);
|
||||
|
||||
User user = this.persistenceHandler.getUser(username);
|
||||
if (user == null)
|
||||
return null;
|
||||
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_GET_USER, new Tuple(null, user)));
|
||||
return user.asUserRep();
|
||||
}
|
||||
|
||||
public Map<String, String> getPolicyDefs(Certificate certificate) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_ACTION,
|
||||
DefaultPrivilegeHandler.PRIVILEGE_ACTION_GET_POLICIES));
|
||||
|
||||
Map<String, String> policyDef = new HashMap<>(this.policyMap.size());
|
||||
for (Map.Entry<String, Class<PrivilegePolicy>> entry : this.policyMap.entrySet()) {
|
||||
policyDef.put(entry.getKey(), entry.getValue().getName());
|
||||
}
|
||||
return policyDef;
|
||||
}
|
||||
|
||||
public List<RoleRep> getRoles(Certificate certificate) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_GET_ROLE);
|
||||
|
||||
Stream<Role> rolesStream = this.persistenceHandler.getAllRoles().stream();
|
||||
|
||||
// validate access to each role
|
||||
rolesStream = rolesStream.filter(role -> prvCtx.hasPrivilege(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_GET_ROLE, new Tuple(null, role))));
|
||||
|
||||
return rolesStream.map(Role::asRoleRep).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<UserRep> getUsers(Certificate certificate) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_GET_USER);
|
||||
|
||||
Stream<User> usersStream = this.persistenceHandler.getAllUsers().stream();
|
||||
|
||||
// validate access to each user
|
||||
usersStream = usersStream.filter(user -> prvCtx.hasPrivilege(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_GET_USER, new Tuple(null, user))));
|
||||
|
||||
return usersStream.map(User::asUserRep).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<UserRep> queryUsers(Certificate certificate, UserRep selectorRep) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_GET_USER);
|
||||
|
||||
String selUserId = selectorRep.getUserId();
|
||||
String selUsername = selectorRep.getUsername();
|
||||
String selFirstName = selectorRep.getFirstname();
|
||||
String selLastName = selectorRep.getLastname();
|
||||
UserState selUserState = selectorRep.getUserState();
|
||||
Locale selLocale = selectorRep.getLocale();
|
||||
Set<String> selGroups = selectorRep.getGroups();
|
||||
Set<String> selRoles = selectorRep.getRoles();
|
||||
Map<String, String> selPropertyMap = selectorRep.getProperties();
|
||||
|
||||
List<UserRep> result = new ArrayList<>();
|
||||
List<User> allUsers = this.persistenceHandler.getAllUsers();
|
||||
for (User user : allUsers) {
|
||||
|
||||
if (!prvCtx.hasPrivilege(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_GET_USER, new Tuple(null, user))))
|
||||
continue;
|
||||
|
||||
// selections
|
||||
boolean userIdSelected;
|
||||
boolean usernameSelected;
|
||||
boolean firstNameSelected;
|
||||
boolean lastNameSelected;
|
||||
boolean userStateSelected;
|
||||
boolean localeSelected;
|
||||
boolean roleSelected;
|
||||
boolean groupSelected;
|
||||
boolean propertySelected;
|
||||
|
||||
// userId
|
||||
userIdSelected = isEmpty(selUserId) || selUserId.equals(user.getUserId());
|
||||
|
||||
// username
|
||||
usernameSelected = isEmpty(selUsername) || selUsername.equals(user.getUsername());
|
||||
|
||||
// firstname
|
||||
firstNameSelected = isEmpty(selFirstName) || selFirstName.equals(user.getFirstname());
|
||||
|
||||
// lastname
|
||||
lastNameSelected = isEmpty(selLastName) || selLastName.equals(user.getLastname());
|
||||
|
||||
// user state
|
||||
userStateSelected = selUserState == null || selUserState.equals(user.getUserState());
|
||||
|
||||
// locale
|
||||
localeSelected = selLocale == null || selLocale.equals(user.getLocale());
|
||||
|
||||
// groups
|
||||
groupSelected = isSelectedByGroup(selGroups, user.getGroups());
|
||||
|
||||
// roles
|
||||
roleSelected = isSelectedByRole(selRoles, user.getRoles());
|
||||
|
||||
// properties
|
||||
propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties());
|
||||
|
||||
boolean selected = userIdSelected && usernameSelected && firstNameSelected && lastNameSelected &&
|
||||
userStateSelected && localeSelected && groupSelected && roleSelected && propertySelected;
|
||||
|
||||
if (selected)
|
||||
result.add(user.asUserRep());
|
||||
}
|
||||
|
||||
result.sort(Comparator.comparing(UserRep::getUsername));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given properties contains values which are contained in the selectionMap. If the selectionMap is
|
||||
* null or empty, then true is returned. If a key/value pair from the selectionMap is not in the properties, then
|
||||
* false is returned
|
||||
*
|
||||
* @param selectionMap the map defining the expected properties
|
||||
* @param properties the properties which must be a sub set of selectionMap to have this method return true
|
||||
*
|
||||
* @return If the selectionMap is null or empty, then true is returned. If a key/value pair from the selectionMap is
|
||||
* not in the properties, then false is returned
|
||||
*/
|
||||
boolean isSelectedByProperty(Map<String, String> selectionMap, Map<String, String> properties) {
|
||||
|
||||
if (selectionMap == null)
|
||||
return true;
|
||||
|
||||
if (selectionMap.isEmpty() && properties.isEmpty())
|
||||
return true;
|
||||
|
||||
for (String selKey : selectionMap.keySet()) {
|
||||
|
||||
String value = properties.get(selKey);
|
||||
if (value == null || !value.equals(selectionMap.get(selKey)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given roles contains the given selectionRoles, if this is the case, or selectionRoles is null or
|
||||
* empty, then true is returned, otherwise false
|
||||
*
|
||||
* @param selectionRoles the required roles
|
||||
* @param roles the roles to check if they contain the selectionRoles
|
||||
*
|
||||
* @return Checks if the given roles contains the given selectionRoles, if this is the case, or selectionRoles is
|
||||
* null or empty, then true is returned, otherwise false
|
||||
*/
|
||||
boolean isSelectedByRole(Set<String> selectionRoles, Set<String> roles) {
|
||||
return selectionRoles == null || roles.containsAll(selectionRoles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given groups contains the given selectionGroups, if this is the case, or selectionGroups is null or
|
||||
* empty, then true is returned, otherwise false
|
||||
*
|
||||
* @param selectionGroups the required groups
|
||||
* @param groups the groups to check if they contain the selectionGroups
|
||||
*
|
||||
* @return Checks if the given groups contains the given selectionGroups, if this is the case, or selectionGroups is
|
||||
* null or empty, then true is returned, otherwise false
|
||||
*/
|
||||
boolean isSelectedByGroup(Set<String> selectionGroups, Set<String> groups) {
|
||||
return selectionGroups == null || groups.containsAll(selectionGroups);
|
||||
}
|
||||
|
||||
public UserRep addUser(Certificate certificate, UserRep userRepParam, char[] password) {
|
||||
try {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_ADD_USER);
|
||||
|
||||
// make sure userId is not set
|
||||
if (isNotEmpty(userRepParam.getUserId()))
|
||||
throw new PrivilegeModelException("UserId can not be set when adding a new user!");
|
||||
|
||||
UserRep userRep = userRepParam.getCopy();
|
||||
|
||||
// set userId
|
||||
userRep.setUserId(getUniqueId());
|
||||
|
||||
// first validate user
|
||||
userRep.validate();
|
||||
|
||||
validateGroupsExist(userRep);
|
||||
validateRolesExist(userRep);
|
||||
|
||||
// validate user does not already exist
|
||||
if (this.persistenceHandler.getUser(userRep.getUsername()) != null) {
|
||||
String msg = "User {0} can not be added as it already exists!";
|
||||
throw new PrivilegeModelException(MessageFormat.format(msg, userRep.getUsername()));
|
||||
}
|
||||
|
||||
UserHistory history = UserHistory.EMPTY;
|
||||
PasswordCrypt passwordCrypt = null;
|
||||
if (password != null) {
|
||||
|
||||
// validate password meets basic requirements
|
||||
this.privilegeHandler.validatePassword(certificate.getLocale(), password);
|
||||
|
||||
// get new salt for user
|
||||
byte[] salt = this.privilegeHandler.getEncryptionHandler().nextSalt();
|
||||
|
||||
// hash password
|
||||
passwordCrypt = this.privilegeHandler.getEncryptionHandler().hashPassword(password, salt);
|
||||
|
||||
history = history.withLastPasswordChange(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
// create new user
|
||||
User newUser = createUser(userRep, history, passwordCrypt, false);
|
||||
|
||||
// detect privilege conflicts
|
||||
assertNoPrivilegeConflict(newUser);
|
||||
|
||||
// validate this user may create such a user
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_ADD_USER, new Tuple(null, newUser)));
|
||||
|
||||
// delegate to persistence handler
|
||||
this.persistenceHandler.addUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Created new user " + newUser.getUsername());
|
||||
|
||||
return newUser.asUserRep();
|
||||
|
||||
} finally {
|
||||
clearPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
public void addOrUpdateUsers(Certificate certificate, List<UserRep> userReps) throws PrivilegeException {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_ADD_USER);
|
||||
|
||||
List<User> toCreate = new ArrayList<>();
|
||||
List<User> toUpdate = new ArrayList<>();
|
||||
|
||||
for (UserRep e : userReps) {
|
||||
UserRep userRep = e.getCopy();
|
||||
|
||||
User user;
|
||||
User existingUser = this.persistenceHandler.getUser(userRep.getUsername());
|
||||
|
||||
if (existingUser == null) {
|
||||
|
||||
// add user
|
||||
|
||||
// make sure userId is not set
|
||||
if (isNotEmpty(userRep.getUserId()))
|
||||
throw new PrivilegeModelException("UserId can not be set when adding a new user!");
|
||||
|
||||
// set userId
|
||||
userRep.setUserId(getUniqueId());
|
||||
|
||||
// first validate user
|
||||
userRep.validate();
|
||||
|
||||
validateGroupsExist(userRep);
|
||||
validateRolesExist(userRep);
|
||||
|
||||
// create new user
|
||||
user = createUser(userRep, UserHistory.EMPTY, null, false);
|
||||
|
||||
// detect privilege conflicts
|
||||
assertNoPrivilegeConflict(user);
|
||||
|
||||
// validate this user may create such a user
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_ADD_USER, new Tuple(null, user)));
|
||||
|
||||
toCreate.add(user);
|
||||
DefaultPrivilegeHandler.logger.info("Creating new user " + user.getUsername());
|
||||
|
||||
} else {
|
||||
|
||||
// update user
|
||||
|
||||
if (userRep.getUserId() == null)
|
||||
userRep.setUserId(existingUser.getUserId());
|
||||
|
||||
user = createUser(userRep, existingUser.getHistory(), existingUser.getPasswordCrypt(),
|
||||
existingUser.isPasswordChangeRequested());
|
||||
|
||||
// detect privilege conflicts
|
||||
assertNoPrivilegeConflict(user);
|
||||
|
||||
// validate this user may modify this user
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_MODIFY_USER,
|
||||
new Tuple(existingUser, user)));
|
||||
|
||||
toUpdate.add(user);
|
||||
DefaultPrivilegeHandler.logger.info("Updating existing user " + user.getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
// delegate to persistence handler
|
||||
toCreate.forEach(this.persistenceHandler::addUser);
|
||||
toUpdate.forEach(this.persistenceHandler::replaceUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Created " + toCreate.size() + " users");
|
||||
DefaultPrivilegeHandler.logger.info("Updated " + toUpdate.size() + " users");
|
||||
}
|
||||
|
||||
private void assertNoPrivilegeConflict(User user) {
|
||||
if (!this.privilegeConflictResolution.isStrict())
|
||||
return;
|
||||
Map<String, String> privilegeNames = new HashMap<>();
|
||||
List<String> conflicts = detectPrivilegeConflicts(privilegeNames, user);
|
||||
if (conflicts.isEmpty())
|
||||
return;
|
||||
String msg = String.join("\n", conflicts);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
|
||||
private void assertNoPrivilegeConflict(Role role) {
|
||||
if (!this.privilegeConflictResolution.isStrict())
|
||||
return;
|
||||
|
||||
Map<String, String> privilegeNames = new HashMap<>();
|
||||
for (String privilegeName : role.getPrivilegeNames()) {
|
||||
privilegeNames.put(privilegeName, role.getName());
|
||||
}
|
||||
|
||||
List<String> conflicts = new ArrayList<>();
|
||||
List<User> users = this.persistenceHandler.getAllUsers();
|
||||
for (User user : users) {
|
||||
if (user.hasRole(role.getName()))
|
||||
conflicts.addAll(detectPrivilegeConflicts(privilegeNames, user));
|
||||
}
|
||||
|
||||
if (!conflicts.isEmpty()) {
|
||||
String msg = String.join("\n", conflicts);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> detectPrivilegeConflicts(Map<String, String> privilegeNames, User user) {
|
||||
List<String> conflicts = new ArrayList<>();
|
||||
|
||||
Set<String> userRoles = user.getRoles();
|
||||
for (String roleName : userRoles) {
|
||||
Role role = this.persistenceHandler.getRole(roleName);
|
||||
if (role == null)
|
||||
throw new IllegalStateException("Role " + roleName + " does not exist for user " + user.getUsername());
|
||||
for (String privilegeName : role.getPrivilegeNames()) {
|
||||
String roleOrigin = privilegeNames.get(privilegeName);
|
||||
if (roleOrigin == null) {
|
||||
privilegeNames.put(privilegeName, roleName);
|
||||
} else if (!roleOrigin.equals(roleName)) {
|
||||
String msg = "User {0} has conflicts for privilege {1} on roles {2} and {3}";
|
||||
msg = format(msg, user.getUsername(), privilegeName, roleOrigin, roleName);
|
||||
conflicts.add(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private void validateGroupsExist(UserRep userRep) {
|
||||
for (String group : userRep.getGroups()) {
|
||||
if (this.persistenceHandler.getGroup(group) == null) {
|
||||
String msg = "Can not add/update user {0} as group {1} does not exist!";
|
||||
msg = MessageFormat.format(msg, userRep.getUsername(), group);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRolesExist(UserRep userRep) {
|
||||
for (String role : userRep.getRoles()) {
|
||||
if (this.persistenceHandler.getRole(role) == null) {
|
||||
String msg = "Can not add/update user {0} as role {1} does not exist!";
|
||||
msg = MessageFormat.format(msg, userRep.getUsername(), role);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
User createUser(UserRep userRep, UserHistory history, PasswordCrypt passwordCrypt,
|
||||
boolean passwordChangeRequested) {
|
||||
String userId = userRep.getUserId();
|
||||
String userName = userRep.getUsername();
|
||||
String firstName = userRep.getFirstname();
|
||||
String lastName = userRep.getLastname();
|
||||
UserState state = userRep.getUserState();
|
||||
Set<String> groups = userRep.getGroups();
|
||||
Set<String> roles = userRep.getRoles();
|
||||
Locale locale = userRep.getLocale();
|
||||
Map<String, String> properties = userRep.getProperties();
|
||||
return new User(userId, userName, passwordCrypt, firstName, lastName, state, groups, roles, locale, properties,
|
||||
passwordChangeRequested, history);
|
||||
}
|
||||
|
||||
public UserRep updateUser(Certificate certificate, UserRep userRep, char[] password) throws PrivilegeException {
|
||||
try {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_MODIFY_USER);
|
||||
|
||||
// first validate user
|
||||
userRep.validate();
|
||||
|
||||
validateGroupsExist(userRep);
|
||||
validateRolesExist(userRep);
|
||||
|
||||
// validate user exists
|
||||
User existingUser = this.persistenceHandler.getUser(userRep.getUsername());
|
||||
if (existingUser == null) {
|
||||
String msg = "User {0} does not exist!";
|
||||
throw new PrivilegeModelException(MessageFormat.format(msg, userRep.getUsername()));
|
||||
}
|
||||
|
||||
// validate same userId
|
||||
if (!existingUser.getUserId().equals(userRep.getUserId())) {
|
||||
String msg = "UserId of existing user {0} does not match userRep {1}";
|
||||
msg = MessageFormat.format(msg, existingUser.getUserId(), userRep.getUserId());
|
||||
throw new PrivilegeModelException(MessageFormat.format(msg, userRep.getUsername()));
|
||||
}
|
||||
|
||||
UserHistory history = existingUser.getHistory();
|
||||
PasswordCrypt passwordCrypt;
|
||||
if (password == null) {
|
||||
passwordCrypt = existingUser.getPasswordCrypt();
|
||||
} else {
|
||||
|
||||
// validate password meets basic requirements
|
||||
this.privilegeHandler.validatePassword(certificate.getLocale(), password);
|
||||
|
||||
// get new salt for user
|
||||
byte[] salt = this.privilegeHandler.getEncryptionHandler().nextSalt();
|
||||
|
||||
// hash password
|
||||
passwordCrypt = this.privilegeHandler.getEncryptionHandler().hashPassword(password, salt);
|
||||
|
||||
history = history.withLastPasswordChange(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
User newUser = createUser(userRep, history, passwordCrypt, existingUser.isPasswordChangeRequested());
|
||||
|
||||
// detect privilege conflicts
|
||||
assertNoPrivilegeConflict(newUser);
|
||||
|
||||
// validate this user may modify this user
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_MODIFY_USER,
|
||||
new Tuple(existingUser, newUser)));
|
||||
|
||||
// delegate to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Replaced user " + newUser.getUsername());
|
||||
|
||||
return newUser.asUserRep();
|
||||
|
||||
} finally {
|
||||
clearPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
public UserRep removeUser(Certificate certificate, String username) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_USER);
|
||||
|
||||
// validate user exists
|
||||
User existingUser = this.persistenceHandler.getUser(username);
|
||||
if (existingUser == null) {
|
||||
String msg = "Can not remove User {0} because user does not exist!";
|
||||
throw new PrivilegeModelException(MessageFormat.format(msg, username));
|
||||
}
|
||||
|
||||
// validate this user may remove this user
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_USER, new Tuple(null, existingUser)));
|
||||
|
||||
// delegate user removal to persistence handler
|
||||
this.privilegeHandler.invalidSessionsFor(existingUser);
|
||||
this.persistenceHandler.removeUser(username);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Removed user " + username);
|
||||
|
||||
return existingUser.asUserRep();
|
||||
}
|
||||
|
||||
public UserRep setUserLocale(Certificate certificate, String username, Locale locale) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_LOCALE);
|
||||
|
||||
// get User
|
||||
User existingUser = this.persistenceHandler.getUser(username);
|
||||
if (existingUser == null)
|
||||
throw new PrivilegeModelException(MessageFormat.format("User {0} does not exist!", username));
|
||||
|
||||
// create new user
|
||||
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPasswordCrypt(),
|
||||
existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(),
|
||||
existingUser.getGroups(), existingUser.getRoles(), locale, existingUser.getProperties(),
|
||||
existingUser.isPasswordChangeRequested(), existingUser.getHistory());
|
||||
|
||||
// if the user is not setting their own locale, then make sure this user may set this user's locale
|
||||
if (!certificate.getUsername().equals(username)) {
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_LOCALE,
|
||||
new Tuple(existingUser, newUser)));
|
||||
}
|
||||
|
||||
// delegate user replacement to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Set locale to " + locale + " for " + newUser.getUsername());
|
||||
|
||||
return newUser.asUserRep();
|
||||
}
|
||||
|
||||
public void requirePasswordChange(Certificate certificate, String username) throws PrivilegeException {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_REQUIRE_PASSWORD_CHANGE);
|
||||
|
||||
// get User
|
||||
User existingUser = this.persistenceHandler.getUser(username);
|
||||
if (existingUser == null)
|
||||
throw new PrivilegeModelException(MessageFormat.format("User {0} does not exist!", username));
|
||||
|
||||
if (existingUser.getUserState().isRemote())
|
||||
throw new PrivilegeModelException(
|
||||
MessageFormat.format("User {0} is remote and can not set password!", username));
|
||||
|
||||
// create new user
|
||||
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPasswordCrypt(),
|
||||
existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(),
|
||||
existingUser.getGroups(), existingUser.getRoles(), existingUser.getLocale(),
|
||||
existingUser.getProperties(), true, existingUser.getHistory());
|
||||
|
||||
// delegate user replacement to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info(
|
||||
"Requiring user " + newUser.getUsername() + " to change their password on next login.");
|
||||
}
|
||||
|
||||
public void setUserPassword(Certificate certificate, String username, char[] password) {
|
||||
|
||||
// we don't want the user to worry about whitespace
|
||||
username = trimOrEmpty(username);
|
||||
|
||||
try {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD);
|
||||
|
||||
// get User
|
||||
User existingUser = this.persistenceHandler.getUser(username);
|
||||
if (existingUser == null)
|
||||
throw new PrivilegeModelException(MessageFormat.format("User {0} does not exist!", username));
|
||||
|
||||
UserHistory history = existingUser.getHistory();
|
||||
|
||||
PasswordCrypt passwordCrypt = null;
|
||||
if (password != null) {
|
||||
|
||||
// validate password meets basic requirements
|
||||
this.privilegeHandler.validatePassword(certificate.getLocale(), password);
|
||||
|
||||
// get new salt for user
|
||||
byte[] salt = this.privilegeHandler.getEncryptionHandler().nextSalt();
|
||||
|
||||
// hash password
|
||||
passwordCrypt = this.privilegeHandler.getEncryptionHandler().hashPassword(password, salt);
|
||||
|
||||
history = history.withLastPasswordChange(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
// create new user
|
||||
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), passwordCrypt,
|
||||
existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(),
|
||||
existingUser.getGroups(), existingUser.getRoles(), existingUser.getLocale(),
|
||||
existingUser.getProperties(), false, history);
|
||||
|
||||
if (!certificate.getUsername().equals(username)) {
|
||||
// check that the user may change their own password
|
||||
Tuple value = new Tuple(existingUser, newUser);
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD, value));
|
||||
}
|
||||
|
||||
// delegate user replacement to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
if (certificate.getUsage() == Usage.SET_PASSWORD)
|
||||
this.privilegeHandler.invalidate(certificate);
|
||||
|
||||
if (password == null)
|
||||
DefaultPrivilegeHandler.logger.info("Cleared password for " + newUser.getUsername());
|
||||
else
|
||||
DefaultPrivilegeHandler.logger.info("Updated password for " + newUser.getUsername());
|
||||
|
||||
} finally {
|
||||
clearPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
public UserRep setUserState(Certificate certificate, String username, UserState state) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_STATE);
|
||||
|
||||
// get User
|
||||
User existingUser = this.persistenceHandler.getUser(username);
|
||||
if (existingUser == null)
|
||||
throw new PrivilegeModelException(MessageFormat.format("User {0} does not exist!", username));
|
||||
|
||||
// create new user
|
||||
User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPasswordCrypt(),
|
||||
existingUser.getFirstname(), existingUser.getLastname(), state, existingUser.getGroups(),
|
||||
existingUser.getRoles(), existingUser.getLocale(), existingUser.getProperties(),
|
||||
existingUser.isPasswordChangeRequested(), existingUser.getHistory());
|
||||
|
||||
// validate that this user may modify this user's state
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_SET_USER_STATE,
|
||||
new Tuple(existingUser, newUser)));
|
||||
|
||||
// delegate user replacement to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Set state of user " + newUser.getUsername() + " to " + state);
|
||||
|
||||
return newUser.asUserRep();
|
||||
}
|
||||
|
||||
public RoleRep addRole(Certificate certificate, RoleRep roleRep) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_ADD_ROLE);
|
||||
|
||||
// first validate role
|
||||
roleRep.validate();
|
||||
|
||||
// validate role does not exist
|
||||
if (this.persistenceHandler.getRole(roleRep.getName()) != null) {
|
||||
String msg = MessageFormat.format("Can not add role {0} as it already exists!", roleRep.getName());
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
|
||||
// create new role from RoleRep
|
||||
Role newRole = Role.of(roleRep);
|
||||
|
||||
// validate that this user may add this new role
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_ADD_ROLE, new Tuple(null, newRole)));
|
||||
|
||||
// validate policy if not null
|
||||
validatePolicies(newRole);
|
||||
|
||||
// delegate to persistence handler
|
||||
this.persistenceHandler.addRole(newRole);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Added new role " + newRole.getName());
|
||||
|
||||
return newRole.asRoleRep();
|
||||
}
|
||||
|
||||
public RoleRep replaceRole(Certificate certificate, RoleRep roleRep) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_MODIFY_ROLE);
|
||||
|
||||
// first validate role
|
||||
roleRep.validate();
|
||||
|
||||
// validate role does exist
|
||||
Role existingRole = this.persistenceHandler.getRole(roleRep.getName());
|
||||
if (existingRole == null) {
|
||||
String msg = MessageFormat.format("Can not replace role {0} as it does not exist!", roleRep.getName());
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
|
||||
// create new role from RoleRep
|
||||
Role newRole = Role.of(roleRep);
|
||||
|
||||
// detect privilege conflicts
|
||||
assertNoPrivilegeConflict(newRole);
|
||||
|
||||
// validate that this user may modify this role
|
||||
prvCtx.validateAction(new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_MODIFY_ROLE,
|
||||
new Tuple(existingRole, newRole)));
|
||||
|
||||
// validate policy if not null
|
||||
validatePolicies(newRole);
|
||||
|
||||
// delegate to persistence handler
|
||||
this.persistenceHandler.replaceRole(newRole);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Replaced role " + newRole.getName());
|
||||
|
||||
// update any existing certificates with new role
|
||||
this.privilegeHandler.updateExistingSessionsWithNewRole(newRole);
|
||||
|
||||
return newRole.asRoleRep();
|
||||
}
|
||||
|
||||
public RoleRep removeRole(Certificate certificate, String roleName) {
|
||||
|
||||
// validate user actually has this type of privilege
|
||||
PrivilegeContext prvCtx = this.privilegeHandler.validate(certificate);
|
||||
prvCtx.assertHasPrivilege(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_ROLE);
|
||||
|
||||
// validate no user is using this role
|
||||
Set<String> roles = new HashSet<>(Collections.singletonList(roleName));
|
||||
UserRep selector = new UserRep(null, null, null, null, null, null, roles, null, null, null);
|
||||
List<UserRep> usersWithRole = this.privilegeHandler.queryUsers(certificate, selector);
|
||||
if (!usersWithRole.isEmpty()) {
|
||||
String usersS = usersWithRole.stream().map(UserRep::getUsername).collect(Collectors.joining(", "));
|
||||
String msg = "The role {0} can not be removed as the following {1} user have the role assigned: {2}";
|
||||
msg = MessageFormat.format(msg, roleName, usersWithRole.size(), usersS);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
|
||||
// validate role exists
|
||||
Role existingRole = this.persistenceHandler.getRole(roleName);
|
||||
if (existingRole == null) {
|
||||
String msg = "Can not remove Role {0} because role does not exist!";
|
||||
throw new PrivilegeModelException(MessageFormat.format(msg, roleName));
|
||||
}
|
||||
|
||||
// validate that this user may remove this role
|
||||
prvCtx.validateAction(
|
||||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_ROLE, new Tuple(null, existingRole)));
|
||||
|
||||
// delegate role removal to persistence handler
|
||||
this.persistenceHandler.removeRole(roleName);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Removed role " + roleName);
|
||||
|
||||
return existingRole.asRoleRep();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the policies which are not null on the privileges of the role exist
|
||||
*
|
||||
* @param role the role for which the policies are to be checked
|
||||
*/
|
||||
public void validatePolicies(Role role) {
|
||||
for (String privilegeName : role.getPrivilegeNames()) {
|
||||
Privilege privilege = role.getPrivilege(privilegeName);
|
||||
String policy = privilege.getPolicy();
|
||||
if (policy != null && !this.policyMap.containsKey(policy)) {
|
||||
String msg = "Policy {0} for Privilege {1} does not exist on role {2}";
|
||||
msg = format(msg, policy, privilege.getName(), role);
|
||||
throw new PrivilegeModelException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passwords should not be kept as strings, as string are immutable, this method thus clears the char array so that
|
||||
* the password is not in memory anymore
|
||||
*
|
||||
* @param password the char array containing the passwort which is to be set to zeroes
|
||||
*/
|
||||
static void clearPassword(char[] password) {
|
||||
if (password != null)
|
||||
Arrays.fill(password, (char) 0);
|
||||
}
|
||||
}
|
|
@ -15,16 +15,16 @@
|
|||
*/
|
||||
package li.strolch.privilege.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.privilege.base.*;
|
||||
import li.strolch.privilege.model.*;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The {@link PrivilegeHandler} is the centrally exposed API for accessing the privilege library. It exposes all needed
|
||||
* methods to access Privilege data model objects, modify them and validate if users or roles have privileges to perform
|
||||
|
@ -212,10 +212,8 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns a {@link UserRep} for the given username
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the name of the {@link UserRep} to return
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the name of the {@link UserRep} to return
|
||||
*
|
||||
* @return the {@link UserRep} for the given username, or null if it was not found
|
||||
*/
|
||||
|
@ -224,10 +222,8 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns a {@link RoleRep} for the given roleName
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName
|
||||
* the name of the {@link RoleRep} to return
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName the name of the {@link RoleRep} to return
|
||||
*
|
||||
* @return the {@link RoleRep} for the given roleName, or null if it was not found
|
||||
*/
|
||||
|
@ -236,8 +232,7 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns the map of {@link PrivilegePolicy} definitions
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
*
|
||||
* @return the map of {@link PrivilegePolicy} definitions
|
||||
*/
|
||||
|
@ -246,8 +241,7 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns the list of {@link Certificate Certificates}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
*
|
||||
* @return the list of {@link Certificate Certificates}
|
||||
*/
|
||||
|
@ -256,8 +250,7 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns all {@link RoleRep RoleReps}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
*
|
||||
* @return the list of {@link RoleRep RoleReps}
|
||||
*/
|
||||
|
@ -266,8 +259,7 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Returns all {@link UserRep UserReps}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
*
|
||||
* @return the list of {@link UserRep UserReps}
|
||||
*/
|
||||
|
@ -277,10 +269,8 @@ public interface PrivilegeHandler {
|
|||
* Method to query {@link UserRep} which meet the criteria set in the given {@link UserRep}. Null fields mean the
|
||||
* fields are irrelevant.
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param selectorRep
|
||||
* the {@link UserRep} to use as criteria selection
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param selectorRep the {@link UserRep} to use as criteria selection
|
||||
*
|
||||
* @return a list of {@link UserRep}s which fit the given criteria
|
||||
*/
|
||||
|
@ -289,72 +279,30 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Removes the user with the given username
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the user to remove
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the username of the user to remove
|
||||
*
|
||||
* @return the {@link UserRep} of the user removed, or null if the user did not exist
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
*/
|
||||
UserRep removeUser(Certificate certificate, String username) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Removes the role with the given roleName from the user with the given username
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the user from which the role is to be removed
|
||||
* @param roleName
|
||||
* the roleName of the role to remove from the user
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
*/
|
||||
UserRep removeRoleFromUser(Certificate certificate, String username, String roleName) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Removes the role with the given roleName
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName
|
||||
* the roleName of the role to remove
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName the roleName of the role to remove
|
||||
*
|
||||
* @return the {@link RoleRep} of the role removed, or null if the role did not exist
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or the role is still in use by a user
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate or the role is still in use by a
|
||||
* user
|
||||
*/
|
||||
RoleRep removeRole(Certificate certificate, String roleName) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Removes the privilege with the given privilegeName from the role with the given roleName
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName
|
||||
* the roleName of the role from which the privilege is to be removed
|
||||
* @param privilegeName
|
||||
* the privilegeName of the privilege to remove from the role
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
*/
|
||||
RoleRep removePrivilegeFromRole(Certificate certificate, String roleName, String privilegeName)
|
||||
throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Adds a new user with the information from this {@link UserRep}
|
||||
|
@ -365,18 +313,14 @@ public interface PrivilegeHandler {
|
|||
* the requirements of the implementation under {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
* </p>
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userRep
|
||||
* the {@link UserRep} containing the information to create the new {@link User}
|
||||
* @param password
|
||||
* the password of the new user. If the password is null, then this is accepted but the user can not login,
|
||||
* otherwise the password must be validated against {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userRep the {@link UserRep} containing the information to create the new {@link User}
|
||||
* @param password the password of the new user. If the password is null, then this is accepted but the user can
|
||||
* not login, otherwise the password must be validated against
|
||||
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or the user already exists
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate or the user already exists
|
||||
*/
|
||||
UserRep addUser(Certificate certificate, UserRep userRep, char[] password) throws PrivilegeException;
|
||||
|
||||
|
@ -384,10 +328,8 @@ public interface PrivilegeHandler {
|
|||
* Allows the bulk adding or updating of users. If the user exists, the user's history and password is kept,
|
||||
* otherwise the user is created without a password
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userReps
|
||||
* the list of users to add or update
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userReps the list of users to add or update
|
||||
*/
|
||||
void addOrUpdateUsers(Certificate certificate, List<UserRep> userReps) throws PrivilegeException;
|
||||
|
||||
|
@ -410,108 +352,39 @@ public interface PrivilegeHandler {
|
|||
* Any other fields will be ignored
|
||||
* </p>
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userRep
|
||||
* the {@link UserRep} with the fields set to their new values
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userRep the {@link UserRep} with the fields set to their new values
|
||||
* @param password the password of the new user. If the password is null, then this is accepted but the user can
|
||||
* not login, otherwise the password must be validated against
|
||||
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or if the user does not exist
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate or if the user does not exist
|
||||
*/
|
||||
UserRep updateUser(Certificate certificate, UserRep userRep) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Replaces the existing user with the information from this {@link UserRep} if the user already exists
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If the password given is null, then the user is created, but can not not login! Otherwise the password must meet
|
||||
* the requirements of the implementation under {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
* </p>
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param userRep
|
||||
* the {@link UserRep} containing the information to replace the existing {@link User}
|
||||
* @param password
|
||||
* the password of the new user. If the password is null, then this is accepted but the user can not login,
|
||||
* otherwise the password must be validated against {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or if the user does not exist
|
||||
*/
|
||||
UserRep replaceUser(Certificate certificate, UserRep userRep, char[] password) throws PrivilegeException;
|
||||
UserRep updateUser(Certificate certificate, UserRep userRep, char[] password) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Adds a new role with the information from this {@link RoleRep}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleRep
|
||||
* the {@link RoleRep} containing the information to create the new {@link Role}
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleRep the {@link RoleRep} containing the information to create the new {@link Role}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or if the role already exists
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate or if the role already exists
|
||||
*/
|
||||
RoleRep addRole(Certificate certificate, RoleRep roleRep) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Replaces the existing role with the information from this {@link RoleRep}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleRep
|
||||
* the {@link RoleRep} containing the information to replace the existing {@link Role}
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleRep the {@link RoleRep} containing the information to replace the existing {@link Role}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or if the role does not exist
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate or if the role does not exist
|
||||
*/
|
||||
RoleRep replaceRole(Certificate certificate, RoleRep roleRep) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Adds the role with the given roleName to the {@link User} with the given username
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the {@link User} to which the role should be added
|
||||
* @param roleName
|
||||
* the roleName of the {@link Role} which should be added to the {@link User}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or if the role does not exist
|
||||
*/
|
||||
UserRep addRoleToUser(Certificate certificate, String username, String roleName) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Adds the {@link PrivilegeRep} to the {@link Role} with the given roleName or replaces it, if it already exists
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param roleName
|
||||
* the roleName of the {@link Role} to which the privilege should be added
|
||||
* @param privilegeRep
|
||||
* the representation of the {@link IPrivilege} which should be added or replaced on the {@link Role}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate or the role does not exist
|
||||
*/
|
||||
RoleRep addOrReplacePrivilegeOnRole(Certificate certificate, String roleName, PrivilegeRep privilegeRep)
|
||||
throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Changes the password for the {@link User} with the given username. If the password is null, then the {@link User}
|
||||
|
@ -523,19 +396,14 @@ public interface PrivilegeHandler {
|
|||
* It should be possible for a user to change their own password
|
||||
* </p>
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the {@link User} for which the password is to be changed
|
||||
* @param password
|
||||
* the new password for this user. If the password is null, then the {@link User} can not login anymore. Otherwise
|
||||
* the password must meet the requirements of the implementation under
|
||||
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the username of the {@link User} for which the password is to be changed
|
||||
* @param password the new password for this user. If the password is null, then the {@link User} can not login
|
||||
* anymore. Otherwise the password must meet the requirements of the implementation under
|
||||
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
*/
|
||||
void setUserPassword(Certificate certificate, String username, char[] password) throws PrivilegeException;
|
||||
|
||||
|
@ -544,105 +412,79 @@ public interface PrivilegeHandler {
|
|||
* Requires the given user to change their password after next login
|
||||
* </p>
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the {@link User} for which the password change is requested
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the username of the {@link User} for which the password change is requested
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
*/
|
||||
void requirePasswordChange(Certificate certificate, String username) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Changes the {@link UserState} of the user
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the {@link User} for which the {@link UserState} is to be changed
|
||||
* @param state
|
||||
* the new state for the user
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the username of the {@link User} for which the {@link UserState} is to be changed
|
||||
* @param state the new state for the user
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
*/
|
||||
UserRep setUserState(Certificate certificate, String username, UserState state) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Changes the {@link Locale} of the user
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username
|
||||
* the username of the {@link User} for which the {@link Locale} is to be changed
|
||||
* @param locale
|
||||
* the new {@link Locale} for the user
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param username the username of the {@link User} for which the {@link Locale} is to be changed
|
||||
* @param locale the new {@link Locale} for the user
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
*/
|
||||
UserRep setUserLocale(Certificate certificate, String username, Locale locale) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Initiate a password reset challenge for the given username
|
||||
*
|
||||
* @param usage
|
||||
* the usage for which the challenge is requested
|
||||
* @param username
|
||||
* the username of the user to initiate the challenge for
|
||||
* @param usage the usage for which the challenge is requested
|
||||
* @param username the username of the user to initiate the challenge for
|
||||
*/
|
||||
void initiateChallengeFor(Usage usage, String username);
|
||||
|
||||
/**
|
||||
* Initiate a password reset challenge for the given username
|
||||
*
|
||||
* @param usage
|
||||
* the usage for which the challenge is requested
|
||||
* @param username
|
||||
* the username of the user to initiate the challenge for
|
||||
* @param source
|
||||
* the source of the challenge
|
||||
* @param usage the usage for which the challenge is requested
|
||||
* @param username the username of the user to initiate the challenge for
|
||||
* @param source the source of the challenge
|
||||
*/
|
||||
void initiateChallengeFor(Usage usage, String username, String source);
|
||||
|
||||
/**
|
||||
* Validate the response of a challenge for the given username
|
||||
*
|
||||
* @param username
|
||||
* the username of the user for which the challenge is to be validated
|
||||
* @param challenge
|
||||
* the challenge from the user
|
||||
* @param username the username of the user for which the challenge is to be validated
|
||||
* @param challenge the challenge from the user
|
||||
*
|
||||
* @return certificate with which the user can access the system with the {@link Usage} set to the value from the
|
||||
* initiated challenge
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if anything goes wrong
|
||||
* @throws PrivilegeException if anything goes wrong
|
||||
*/
|
||||
Certificate validateChallenge(String username, String challenge) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Validate the response of a challenge for the given username
|
||||
*
|
||||
* @param username
|
||||
* the username of the user for which the challenge is to be validated
|
||||
* @param challenge
|
||||
* the challenge from the user
|
||||
* @param source
|
||||
* the source of the challenge validation
|
||||
* @param username the username of the user for which the challenge is to be validated
|
||||
* @param challenge the challenge from the user
|
||||
* @param source the source of the challenge validation
|
||||
*
|
||||
* @return certificate with which the user can access the system with the {@link Usage} set to the value from the
|
||||
* initiated challenge
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if anything goes wrong
|
||||
* @throws PrivilegeException if anything goes wrong
|
||||
*/
|
||||
Certificate validateChallenge(String username, String challenge, String source) throws PrivilegeException;
|
||||
|
||||
|
@ -650,18 +492,14 @@ public interface PrivilegeHandler {
|
|||
* Authenticates a user by validating that a {@link User} for the given username and password exist and then returns
|
||||
* a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @param username
|
||||
* the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||
* @param password
|
||||
* the password with which this user is to be authenticated. Null passwords are not accepted and they must meet
|
||||
* the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
* @param username the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||
* @param password the password with which this user is to be authenticated. Null passwords are not accepted and
|
||||
* they must meet the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||
* @param keepAlive should this session be kept alive
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user credentials are not valid
|
||||
* @throws AccessDeniedException if the user credentials are not valid
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password, boolean keepAlive) throws AccessDeniedException;
|
||||
|
||||
|
@ -669,22 +507,16 @@ public interface PrivilegeHandler {
|
|||
* Authenticates a user by validating that a {@link User} for the given username and password exist and then returns
|
||||
* a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @param username
|
||||
* the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||
* @param password
|
||||
* the password with which this user is to be authenticated. Null passwords are not accepted and they must meet
|
||||
* the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||
* @param source
|
||||
* the source of the authentication request, i.e. remote IP
|
||||
* @param usage
|
||||
* the usage type for this authentication
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
* @param username the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||
* @param password the password with which this user is to be authenticated. Null passwords are not accepted and
|
||||
* they must meet the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||
* @param source the source of the authentication request, i.e. remote IP
|
||||
* @param usage the usage type for this authentication
|
||||
* @param keepAlive should this session be kept alive
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user credentials are not valid
|
||||
* @throws AccessDeniedException if the user credentials are not valid
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive)
|
||||
throws AccessDeniedException;
|
||||
|
@ -692,47 +524,37 @@ public interface PrivilegeHandler {
|
|||
/**
|
||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||
*
|
||||
* @param data
|
||||
* the data to perform the SSO
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
* @param data the data to perform the SSO
|
||||
* @param keepAlive should this session be kept alive
|
||||
*
|
||||
* @return the {@link Certificate} for the user
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if something goes wrong with the SSO
|
||||
* @throws PrivilegeException if something goes wrong with the SSO
|
||||
*/
|
||||
Certificate authenticateSingleSignOn(Object data, boolean keepAlive) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||
*
|
||||
* @param data
|
||||
* the data to perform the SSO
|
||||
* @param source
|
||||
* the source of the SSO authentication
|
||||
* @param keepAlive
|
||||
* may the certificate be kept alive
|
||||
* @param data the data to perform the SSO
|
||||
* @param source the source of the SSO authentication
|
||||
* @param keepAlive may the certificate be kept alive
|
||||
*
|
||||
* @return the {@link Certificate} for the user
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if something goes wrong with the SSO
|
||||
* @throws PrivilegeException if something goes wrong with the SSO
|
||||
*/
|
||||
Certificate authenticateSingleSignOn(Object data, String source, boolean keepAlive) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Refreshes the given certificate's session with a new session, i.e. a new certificate
|
||||
*
|
||||
* @param certificate
|
||||
* the certificate for which to perform a refresh
|
||||
* @param source
|
||||
* the source of the refresh request
|
||||
* @param certificate the certificate for which to perform a refresh
|
||||
* @param source the source of the refresh request
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the certificate is now valid, or refreshing is not allowed
|
||||
* @throws AccessDeniedException if the certificate is now valid, or refreshing is not allowed
|
||||
*/
|
||||
Certificate refresh(Certificate certificate, String source) throws AccessDeniedException;
|
||||
|
||||
|
@ -754,8 +576,7 @@ public interface PrivilegeHandler {
|
|||
* Invalidates the session for the given {@link Certificate}, effectively logging out the user who was authenticated
|
||||
* with the credentials associated to the given {@link Certificate}
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} for which the session is to be invalidated
|
||||
* @param certificate the {@link Certificate} for which the session is to be invalidated
|
||||
*
|
||||
* @return true if the session was still valid and is now invalidated, false otherwise
|
||||
*/
|
||||
|
@ -769,15 +590,12 @@ public interface PrivilegeHandler {
|
|||
* encapsulated state of a user's privileges so that for the duration of a user's call, the user can perform their
|
||||
* actions and do not need to access the {@link PrivilegeHandler} anymore
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} to check
|
||||
* @param certificate the {@link Certificate} to check
|
||||
*
|
||||
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws NotAuthenticatedException
|
||||
* if the certificate has expired
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
* @throws NotAuthenticatedException if the certificate has expired
|
||||
*/
|
||||
PrivilegeContext validate(Certificate certificate) throws PrivilegeException;
|
||||
|
||||
|
@ -786,13 +604,10 @@ public interface PrivilegeHandler {
|
|||
* system user session and that the user exists for the certificate. This method checks if the {@link Certificate}
|
||||
* has been tampered with
|
||||
*
|
||||
* @param ctx
|
||||
* the {@link PrivilegeContext} to check
|
||||
* @param ctx the {@link PrivilegeContext} to check
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this privilege context
|
||||
* @throws NotAuthenticatedException
|
||||
* if the privilege context has expired
|
||||
* @throws PrivilegeException if there is anything wrong with this privilege context
|
||||
* @throws NotAuthenticatedException if the privilege context has expired
|
||||
*/
|
||||
void validateSystemSession(PrivilegeContext ctx) throws PrivilegeException;
|
||||
|
||||
|
@ -804,17 +619,13 @@ public interface PrivilegeHandler {
|
|||
* encapsulated state of a user's privileges so that for the duration of a user's call, the user can perform their
|
||||
* actions and do not need to access the {@link PrivilegeHandler} anymore
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} to check
|
||||
* @param source
|
||||
* the source, e.g. remote IP for this validation request
|
||||
* @param certificate the {@link Certificate} to check
|
||||
* @param source the source, e.g. remote IP for this validation request
|
||||
*
|
||||
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if there is anything wrong with this certificate
|
||||
* @throws NotAuthenticatedException
|
||||
* if the certificate has expired
|
||||
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||
* @throws NotAuthenticatedException if the certificate has expired
|
||||
*/
|
||||
PrivilegeContext validate(Certificate certificate, String source) throws PrivilegeException;
|
||||
|
||||
|
@ -840,15 +651,13 @@ public interface PrivilegeHandler {
|
|||
*
|
||||
* <b>Note:</b> It depends on the underlying {@link PersistenceHandler} implementation if data really is read
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param source
|
||||
* the source of the request
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param source the source of the request
|
||||
*
|
||||
* @return true if the reload was successful, false if something went wrong
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the users of the given certificate does not have the privilege to perform this action
|
||||
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||
* action
|
||||
*/
|
||||
boolean reload(Certificate certificate, String source);
|
||||
|
||||
|
@ -856,28 +665,25 @@ public interface PrivilegeHandler {
|
|||
* Persists any changes to the privilege data model. Changes are thus not persisted immediately, but must be
|
||||
* actively performed
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
*
|
||||
* @return true if changes were persisted, false if no changes were persisted
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the users of the given certificate does not have the privilege to perform this action
|
||||
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||
* action
|
||||
*/
|
||||
boolean persist(Certificate certificate) throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Persists all currently active sessions
|
||||
*
|
||||
* @param certificate
|
||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param source
|
||||
* the source of the request
|
||||
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||
* @param source the source of the request
|
||||
*
|
||||
* @return true if changes were persisted, false if not (i.e. not enabled)
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the users of the given certificate does not have the privilege to perform this action
|
||||
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||
* action
|
||||
*/
|
||||
boolean persistSessions(Certificate certificate, String source) throws AccessDeniedException;
|
||||
|
||||
|
@ -886,15 +692,11 @@ public interface PrivilegeHandler {
|
|||
* has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation
|
||||
* of the given {@link SystemAction} instance
|
||||
*
|
||||
* @param systemUsername
|
||||
* the username of the system user to perform the action as
|
||||
* @param action
|
||||
* the action to be performed as the system user
|
||||
* @param systemUsername the username of the system user to perform the action as
|
||||
* @param action the action to be performed as the system user
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if the user does not exist, or the system action is not allowed
|
||||
* @throws Exception
|
||||
* if anything else goes wrong during execution
|
||||
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||
* @throws Exception if anything else goes wrong during execution
|
||||
*/
|
||||
void runAs(String systemUsername, SystemAction action) throws PrivilegeException, Exception;
|
||||
|
||||
|
@ -903,17 +705,13 @@ public interface PrivilegeHandler {
|
|||
* has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation
|
||||
* of the given {@link SystemAction} instance
|
||||
*
|
||||
* @param systemUsername
|
||||
* the username of the system user to perform the action as
|
||||
* @param action
|
||||
* the action to be performed as the system user
|
||||
* @param systemUsername the username of the system user to perform the action as
|
||||
* @param action the action to be performed as the system user
|
||||
*
|
||||
* @return the action
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if the user does not exist, or the system action is not allowed
|
||||
* @throws Exception
|
||||
* if anything else goes wrong during execution
|
||||
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||
* @throws Exception if anything else goes wrong during execution
|
||||
*/
|
||||
<T> T runWithResult(String systemUsername, SystemActionWithResult<T> action) throws PrivilegeException, Exception;
|
||||
|
||||
|
@ -923,13 +721,11 @@ public interface PrivilegeHandler {
|
|||
* {@link PrivilegeContext} should be open for a longer period of time, or where opening many
|
||||
* {@link PrivilegeContext} is resource intensive e.g. on low power devices.
|
||||
*
|
||||
* @param systemUsername
|
||||
* the username of the system user to perform the action as
|
||||
* @param systemUsername the username of the system user to perform the action as
|
||||
*
|
||||
* @return the action
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if the user does not exist, or the system action is not allowed
|
||||
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||
*/
|
||||
PrivilegeContext openSystemUserContext(String systemUsername) throws PrivilegeException;
|
||||
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
package li.strolch.privilege.handler;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import li.strolch.privilege.helper.LdapHelper;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SimpleLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(SimpleLdapPrivilegeHandler.class);
|
||||
|
||||
private Locale defaultLocale;
|
||||
private String adminUsers;
|
||||
private Map<String, Set<String>> rolesForLdapGroups;
|
||||
private String organisation;
|
||||
private String location;
|
||||
private String realm;
|
||||
|
||||
@Override
|
||||
public void initialize(ScheduledExecutorService executorService, Map<String, String> parameterMap,
|
||||
EncryptionHandler encryptionHandler, PasswordStrengthHandler passwordStrengthHandler,
|
||||
PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler,
|
||||
SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) {
|
||||
|
||||
super.initialize(executorService, parameterMap, encryptionHandler, passwordStrengthHandler, persistenceHandler,
|
||||
userChallengeHandler, ssoHandler, policyMap);
|
||||
|
||||
this.organisation = parameterMap.getOrDefault(ORGANISATION, "");
|
||||
this.location = parameterMap.getOrDefault(LOCATION, "");
|
||||
this.realm = parameterMap.getOrDefault(REALM, "");
|
||||
|
||||
this.defaultLocale = parameterMap.containsKey("defaultLocale") ?
|
||||
Locale.forLanguageTag(parameterMap.get("defaultLocale")) :
|
||||
Locale.getDefault();
|
||||
|
||||
this.adminUsers = parameterMap.get("adminUsers");
|
||||
this.rolesForLdapGroups = getLdapGroupToRolesMappingFromConfig(parameterMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFirstName(String username, Attributes attrs) throws NamingException {
|
||||
String value = getLdapString(attrs, "givenName");
|
||||
return isEmpty(value) ? username : value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLastName(String username, Attributes attrs) throws NamingException {
|
||||
String value = getLdapString(attrs, "sn");
|
||||
return isEmpty(value) ? username : value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, String> buildProperties(String username, Attributes attrs, Set<String> ldapGroups,
|
||||
Set<String> strolchRoles) {
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put(ORGANISATION, this.organisation);
|
||||
properties.put(LOCATION, this.location);
|
||||
properties.put(REALM, this.realm);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Locale getLocale(Attributes attrs) {
|
||||
return this.defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getLdapGroups(String username, Attributes attrs) throws NamingException {
|
||||
Set<String> ldapGroups = LdapHelper.getLdapGroups(attrs);
|
||||
logger.info("User " + username + " has LDAP Groups: ");
|
||||
ldapGroups.forEach(s -> logger.info("- " + s));
|
||||
return ldapGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> mapToStrolchRoles(String username, Set<String> ldapGroups) {
|
||||
Set<String> strolchRoles = new HashSet<>();
|
||||
for (String ldapRole : ldapGroups) {
|
||||
Set<String> foundStrolchRoles = this.rolesForLdapGroups.get(ldapRole);
|
||||
if (foundStrolchRoles != null)
|
||||
strolchRoles.addAll(foundStrolchRoles);
|
||||
}
|
||||
|
||||
// see if this is an admin user
|
||||
if (this.adminUsers.contains(username))
|
||||
strolchRoles = this.rolesForLdapGroups.get("admin");
|
||||
|
||||
return strolchRoles;
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> getLdapGroupToRolesMappingFromConfig(Map<String, String> params) {
|
||||
|
||||
String rolesForLdapGroups = params.get("rolesForLdapGroups");
|
||||
DBC.PRE.assertNotEmpty("No roles mapping for ldap directory groups defined (param: rolesForLdapGroups)",
|
||||
rolesForLdapGroups);
|
||||
|
||||
// rolesForLdapGroups = admin=StrolchAdmin,UserPrivileges;user=UserPrivileges
|
||||
|
||||
String[] ldapGroupRoles = rolesForLdapGroups.split(";");
|
||||
|
||||
Map<String, Set<String>> result = new HashMap<>();
|
||||
for (String ldapGroupRole : ldapGroupRoles) {
|
||||
ldapGroupRole = ldapGroupRole.trim();
|
||||
|
||||
String[] splitGroupRoles = ldapGroupRole.split("=");
|
||||
String ldapGroupName = splitGroupRoles[0];
|
||||
String[] strolchRoles = splitGroupRoles[1].split(",");
|
||||
Set<String> roleNames = new HashSet<>();
|
||||
for (String strolchRole : strolchRoles) {
|
||||
roleNames.add(strolchRole.trim());
|
||||
}
|
||||
|
||||
result.put(ldapGroupName, roleNames);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -15,29 +15,31 @@
|
|||
*/
|
||||
package li.strolch.privilege.handler;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.xml.*;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesDomWriter;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesSaxReader;
|
||||
import li.strolch.privilege.xml.PrivilegeUsersDomWriter;
|
||||
import li.strolch.privilege.xml.PrivilegeUsersSaxReader;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* {@link PersistenceHandler} implementation which reads the configuration from XML files. These configuration is passed
|
||||
|
@ -50,20 +52,24 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
protected static final Logger logger = LoggerFactory.getLogger(XmlPersistenceHandler.class);
|
||||
|
||||
private final Map<String, User> userMap;
|
||||
private final Map<String, Group> groupMap;
|
||||
private final Map<String, Role> roleMap;
|
||||
|
||||
private boolean userMapDirty;
|
||||
private boolean groupMapDirty;
|
||||
private boolean roleMapDirty;
|
||||
|
||||
private Map<String, String> parameterMap;
|
||||
|
||||
private File usersPath;
|
||||
private File groupsPath;
|
||||
private File rolesPath;
|
||||
|
||||
private boolean caseInsensitiveUsername;
|
||||
|
||||
public XmlPersistenceHandler() {
|
||||
this.roleMap = new ConcurrentHashMap<>();
|
||||
this.groupMap = new ConcurrentHashMap<>();
|
||||
this.userMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
|
@ -79,6 +85,13 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Group> getAllGroups() {
|
||||
synchronized (this.groupMap) {
|
||||
return new LinkedList<>(this.groupMap.values());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> getAllRoles() {
|
||||
synchronized (this.roleMap) {
|
||||
|
@ -91,6 +104,11 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
return this.userMap.get(this.caseInsensitiveUsername ? username.toLowerCase() : username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group getGroup(String groupName) {
|
||||
return this.groupMap.get(groupName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Role getRole(String roleName) {
|
||||
return this.roleMap.get(roleName);
|
||||
|
@ -103,6 +121,13 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group removeGroup(String groupName) {
|
||||
Group group = this.groupMap.remove(groupName);
|
||||
this.groupMapDirty = group != null;
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Role removeRole(String roleName) {
|
||||
Role role = this.roleMap.remove(roleName);
|
||||
|
@ -129,6 +154,23 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
this.userMapDirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(Group group) {
|
||||
if (this.groupMap.containsKey(group.name()))
|
||||
throw new IllegalStateException(format("The group {0} already exists!", group.name()));
|
||||
this.groupMap.put(group.name(), group);
|
||||
this.groupMapDirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceGroup(Group group) {
|
||||
if (!this.groupMap.containsKey(group.name()))
|
||||
throw new IllegalStateException(
|
||||
format("The group {0} can not be replaced as it does not exist!", group.name()));
|
||||
this.groupMap.put(group.name(), group);
|
||||
this.groupMapDirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRole(Role role) {
|
||||
if (this.roleMap.containsKey(role.getName()))
|
||||
|
@ -149,9 +191,10 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
/**
|
||||
* Initializes this {@link XmlPersistenceHandler} by reading the following parameters:
|
||||
* <ul>
|
||||
* <li>{@link XmlConstants#XML_PARAM_BASE_PATH}</li>
|
||||
* <li>{@link XmlConstants#XML_PARAM_USERS_FILE}</li>
|
||||
* <li>{@link XmlConstants#XML_PARAM_ROLES_FILE}</li>
|
||||
* <li>{@link XmlConstants#PARAM_BASE_PATH}</li>
|
||||
* <li>{@link XmlConstants#PARAM_USERS_FILE}</li>
|
||||
* <li>{@link XmlConstants#PARAM_GROUPS_FILE}</li>
|
||||
* <li>{@link XmlConstants#PARAM_ROLES_FILE}</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
|
@ -159,58 +202,50 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
this.parameterMap = Map.copyOf(paramsMap);
|
||||
|
||||
// get and validate base bath
|
||||
String basePath = this.parameterMap.get(XML_PARAM_BASE_PATH);
|
||||
String basePath = this.parameterMap.get(PARAM_BASE_PATH);
|
||||
File basePathF = new File(basePath);
|
||||
if (!basePathF.exists() && !basePathF.isDirectory()) {
|
||||
String msg = "[{0}] Defined parameter {1} does not point to a valid path at {2}";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_BASE_PATH, basePathF.getAbsolutePath());
|
||||
msg = format(msg, PersistenceHandler.class.getName(), PARAM_BASE_PATH, basePathF.getAbsolutePath());
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
// get users file name
|
||||
String usersFileName = this.parameterMap.get(XML_PARAM_USERS_FILE);
|
||||
if (StringHelper.isEmpty(usersFileName)) {
|
||||
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_USERS_FILE);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
// get roles file name
|
||||
String rolesFileName = this.parameterMap.get(XML_PARAM_ROLES_FILE);
|
||||
if (StringHelper.isEmpty(rolesFileName)) {
|
||||
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_ROLES_FILE);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
// validate users file exists
|
||||
String usersPathS = basePath + "/" + usersFileName;
|
||||
File usersPath = new File(usersPathS);
|
||||
if (!usersPath.exists()) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid as users file does not exist at path {2}";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_USERS_FILE, usersPath.getAbsolutePath());
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
// validate roles file exists
|
||||
String rolesPathS = basePath + "/" + rolesFileName;
|
||||
File rolesPath = new File(rolesPathS);
|
||||
if (!rolesPath.exists()) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid as roles file does not exist at path {2}";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_ROLES_FILE, rolesPath.getAbsolutePath());
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
File usersPath = getFile(basePath, PARAM_USERS_FILE, PARAM_USERS_FILE_DEF, true);
|
||||
File groupsPath = getFile(basePath, PARAM_GROUPS_FILE, PARAM_GROUPS_FILE_DEF, false);
|
||||
File rolesPath = getFile(basePath, PARAM_ROLES_FILE, PARAM_ROLES_FILE_DEF, true);
|
||||
|
||||
// save path to model
|
||||
this.usersPath = usersPath;
|
||||
this.groupsPath = groupsPath;
|
||||
this.rolesPath = rolesPath;
|
||||
|
||||
this.caseInsensitiveUsername = Boolean.parseBoolean(this.parameterMap.get(PARAM_CASE_INSENSITIVE_USERNAME));
|
||||
this.caseInsensitiveUsername = !this.parameterMap.containsKey(PARAM_CASE_INSENSITIVE_USERNAME) ||
|
||||
parseBoolean(this.parameterMap.get(PARAM_CASE_INSENSITIVE_USERNAME));
|
||||
|
||||
if (reload())
|
||||
logger.info("Privilege Data loaded.");
|
||||
}
|
||||
|
||||
private File getFile(String basePath, String param, String defaultValue, boolean required) {
|
||||
String fileName = this.parameterMap.get(param);
|
||||
if (isEmpty(fileName)) {
|
||||
fileName = defaultValue;
|
||||
String msg = "[{0}] Parameter {1} is not defined, using default {2}!";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), param, defaultValue);
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
String path = basePath + "/" + fileName;
|
||||
File file = new File(path);
|
||||
if (required && !file.exists()) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid as file does not exist at path {2}";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), param, file.getAbsolutePath());
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the XML configuration files which contain the model. Which configuration files are parsed was defined in
|
||||
* the while calling {@link #initialize(Map)}
|
||||
|
@ -224,6 +259,10 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
PrivilegeUsersSaxReader usersXmlHandler = new PrivilegeUsersSaxReader(this.caseInsensitiveUsername);
|
||||
XmlHelper.parseDocument(this.usersPath, usersXmlHandler);
|
||||
|
||||
PrivilegeGroupsSaxReader groupsXmlHandler = new PrivilegeGroupsSaxReader();
|
||||
if (this.groupsPath.exists())
|
||||
XmlHelper.parseDocument(this.groupsPath, groupsXmlHandler);
|
||||
|
||||
PrivilegeRolesSaxReader rolesXmlHandler = new PrivilegeRolesSaxReader();
|
||||
XmlHelper.parseDocument(this.rolesPath, rolesXmlHandler);
|
||||
|
||||
|
@ -233,6 +272,12 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
this.roleMap.putAll(rolesXmlHandler.getRoles());
|
||||
}
|
||||
|
||||
// GROUPS
|
||||
synchronized (this.groupMap) {
|
||||
this.groupMap.clear();
|
||||
this.groupMap.putAll(groupsXmlHandler.getGroups());
|
||||
}
|
||||
|
||||
// USERS
|
||||
synchronized (this.userMap) {
|
||||
this.userMap.clear();
|
||||
|
@ -240,21 +285,40 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
}
|
||||
|
||||
this.userMapDirty = false;
|
||||
this.groupMapDirty = false;
|
||||
this.roleMapDirty = false;
|
||||
|
||||
logger.info(format("Read {0} Users", this.userMap.size()));
|
||||
logger.info(format("Read {0} Groups", this.groupMap.size()));
|
||||
logger.info(format("Read {0} Roles", this.roleMap.size()));
|
||||
|
||||
// validate referenced roles exist
|
||||
// validate referenced elements exist
|
||||
for (User user : this.userMap.values()) {
|
||||
for (String roleName : user.getRoles()) {
|
||||
|
||||
// validate that role exists
|
||||
if (getRole(roleName) == null) {
|
||||
logger.error(
|
||||
format("Role {0} does not exist referenced by user {1}", roleName, user.getUsername()));
|
||||
}
|
||||
}
|
||||
|
||||
for (String groupName : user.getGroups()) {
|
||||
// validate that group exists
|
||||
if (getGroup(groupName) == null) {
|
||||
logger.error(
|
||||
format("Group {0} does not exist referenced by user {1}", groupName, user.getUsername()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate referenced roles exist on groups
|
||||
for (Group group : this.groupMap.values()) {
|
||||
for (String roleName : group.roles()) {
|
||||
// validate that role exists
|
||||
if (getRole(roleName) == null) {
|
||||
logger.error(format("Role {0} does not exist referenced by group {1}", roleName, group.name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -264,49 +328,34 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
|||
* Writes the model to the XML files. Where the files are written to was defined in the {@link #initialize(Map)}
|
||||
*/
|
||||
@Override
|
||||
public boolean persist() {
|
||||
|
||||
public boolean persist() throws XMLStreamException, IOException {
|
||||
long start = System.nanoTime();
|
||||
|
||||
// get users file name
|
||||
String usersFileName = this.parameterMap.get(XML_PARAM_USERS_FILE);
|
||||
if (usersFileName == null || usersFileName.isEmpty()) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_USERS_FILE);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
// get roles file name
|
||||
String rolesFileName = this.parameterMap.get(XML_PARAM_ROLES_FILE);
|
||||
if (rolesFileName == null || rolesFileName.isEmpty()) {
|
||||
String msg = "[{0}] Defined parameter {1} is invalid";
|
||||
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_ROLES_FILE);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
boolean saved = false;
|
||||
|
||||
// get users file
|
||||
// write users file
|
||||
if (this.userMapDirty) {
|
||||
// delegate writing
|
||||
PrivilegeUsersDomWriter modelWriter = new PrivilegeUsersDomWriter(getAllUsers(), this.usersPath);
|
||||
modelWriter.write();
|
||||
|
||||
new PrivilegeUsersSaxWriter(getAllUsers(), this.usersPath).write();
|
||||
this.userMapDirty = false;
|
||||
saved = true;
|
||||
}
|
||||
|
||||
// get roles file
|
||||
if (this.roleMapDirty) {
|
||||
// delegate writing
|
||||
PrivilegeRolesDomWriter modelWriter = new PrivilegeRolesDomWriter(getAllRoles(), this.rolesPath);
|
||||
modelWriter.write();
|
||||
// write groups file
|
||||
if (this.groupMapDirty) {
|
||||
new PrivilegeGroupsSaxWriter(getAllGroups(), this.groupsPath).write();
|
||||
this.groupMapDirty = false;
|
||||
saved = true;
|
||||
}
|
||||
|
||||
// write roles file
|
||||
if (this.roleMapDirty) {
|
||||
new PrivilegeRolesSaxWriter(getAllRoles(), this.rolesPath).write();
|
||||
this.roleMapDirty = false;
|
||||
saved = true;
|
||||
}
|
||||
|
||||
logger.info("Persist took " + (formatNanoDuration(System.nanoTime() - start)));
|
||||
long tookNanos = System.nanoTime() - start;
|
||||
if (TimeUnit.NANOSECONDS.toMillis(tookNanos) > 100)
|
||||
logger.warn("Persist took " + (formatNanoDuration(tookNanos)));
|
||||
return saved;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.privilege.model.internal.PasswordCrypt.buildPasswordString;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -111,9 +110,9 @@ public class PasswordCreator {
|
|||
}
|
||||
|
||||
Map<String, String> parameterMap = new HashMap<>();
|
||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_ALGORITHM, hashAlgorithm);
|
||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_ITERATIONS, String.valueOf(iterations));
|
||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_KEY_LENGTH, String.valueOf(keyLength));
|
||||
parameterMap.put(XmlConstants.PARAM_HASH_ALGORITHM, hashAlgorithm);
|
||||
parameterMap.put(XmlConstants.PARAM_HASH_ITERATIONS, String.valueOf(iterations));
|
||||
parameterMap.put(XmlConstants.PARAM_HASH_KEY_LENGTH, String.valueOf(keyLength));
|
||||
|
||||
DefaultEncryptionHandler encryptionHandler = new DefaultEncryptionHandler();
|
||||
encryptionHandler.initialize(parameterMap);
|
||||
|
@ -136,15 +135,15 @@ public class PasswordCreator {
|
|||
byte[] salt = saltS.getBytes();
|
||||
|
||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, salt);
|
||||
String passwordHashS = StringHelper.toHexString(passwordCrypt.getPassword());
|
||||
String passwordHashS = StringHelper.toHexString(passwordCrypt.password());
|
||||
System.out.println("Hash is: " + passwordHashS);
|
||||
System.out.println("Salt is: " + saltS);
|
||||
System.out.println();
|
||||
|
||||
System.out.println(
|
||||
XmlConstants.XML_ATTR_PASSWORD + "=\"" + passwordHashS + "\" " + XmlConstants.XML_ATTR_SALT +
|
||||
"=\"" + saltS + "\"");
|
||||
System.out.println(XmlConstants.XML_ATTR_PASSWORD + "=\"" + passwordCrypt.buildPasswordString() + "\"");
|
||||
XmlConstants.ATTR_PASSWORD + "=\"" + passwordHashS + "\" " + XmlConstants.ATTR_SALT + "=\"" +
|
||||
saltS + "\"");
|
||||
System.out.println(XmlConstants.ATTR_PASSWORD + "=\"" + passwordCrypt.buildPasswordString() + "\"");
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
package li.strolch.privilege.helper;
|
||||
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesSaxReader;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesSaxWriter;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesDomWriter;
|
||||
import li.strolch.privilege.xml.PrivilegeRolesSaxReader;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
|
||||
public class WriteRolesFileHelper {
|
||||
|
||||
public static void main(String[] args) {
|
||||
public static void main(String[] args) throws XMLStreamException, IOException {
|
||||
|
||||
if (args.length != 2)
|
||||
throw new IllegalStateException("Usage: <src> <dst>");
|
||||
|
@ -31,7 +33,7 @@ public class WriteRolesFileHelper {
|
|||
Map<String, Role> rolesMap = xmlHandler.getRoles();
|
||||
List<Role> roles = new ArrayList<>(rolesMap.values());
|
||||
|
||||
PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, dst);
|
||||
PrivilegeRolesSaxWriter configSaxWriter = new PrivilegeRolesSaxWriter(roles, dst);
|
||||
configSaxWriter.write();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,298 +23,69 @@ package li.strolch.privilege.helper;
|
|||
@SuppressWarnings("nls")
|
||||
public class XmlConstants {
|
||||
|
||||
/**
|
||||
* XML_ROOT_PRIVILEGE_CONTAINER = "PrivilegeContainer" :
|
||||
*/
|
||||
public static final String XML_ROOT_PRIVILEGE = "Privilege";
|
||||
|
||||
/**
|
||||
* XML_CONTAINER = "Container" :
|
||||
*/
|
||||
public static final String XML_CONTAINER = "Container";
|
||||
|
||||
/**
|
||||
* XML_POLICIES = "Policies" :
|
||||
*/
|
||||
public static final String XML_POLICIES = "Policies";
|
||||
|
||||
/**
|
||||
* XML_PRIVILEGES = "Privileges" :
|
||||
*/
|
||||
public static final String XML_PRIVILEGES = "Privileges";
|
||||
|
||||
/**
|
||||
* XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles" :
|
||||
*/
|
||||
public static final String XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles";
|
||||
|
||||
/**
|
||||
* XML_ROOT_CERTIFICATES = "Certificates" :
|
||||
*/
|
||||
public static final String XML_ROOT_CERTIFICATES = "Certificates";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_USER_CHALLENGE = "UserChallengeHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_USER_CHALLENGE = "UserChallengeHandler";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_PERSISTENCE = "PersistenceHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_PERSISTENCE = "PersistenceHandler";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_ENCRYPTION = "EncryptionHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_ENCRYPTION = "PasswordStrengthHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_PASSWORD_STRENGTH = "PasswordStrengthHandler";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_ENCRYPTION = "SsoHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_SSO = "SsoHandler";
|
||||
|
||||
/**
|
||||
* XML_HANDLER_PRIVILEGE = "PrivilegeHandler" :
|
||||
*/
|
||||
public static final String XML_HANDLER_PRIVILEGE = "PrivilegeHandler";
|
||||
|
||||
/**
|
||||
* XML_ROLES = "Roles" :
|
||||
*/
|
||||
public static final String XML_ROLES = "Roles";
|
||||
|
||||
/**
|
||||
* XML_ROLE = "Role" :
|
||||
*/
|
||||
public static final String XML_ROLE = "Role";
|
||||
|
||||
/**
|
||||
* XML_USERS = "Users" :
|
||||
*/
|
||||
public static final String XML_USERS = "Users";
|
||||
|
||||
/**
|
||||
* XML_CERTIFICATE = "Certificate" :
|
||||
*/
|
||||
public static final String XML_CERTIFICATE = "Certificate";
|
||||
|
||||
/**
|
||||
* XML_SESSION_DATA = "SessionData" :
|
||||
*/
|
||||
public static final String XML_SESSION_DATA = "SessionData";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_USER = "User";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_HISTORY = "History";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_FIRST_LOGIN = "FirstLogin";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_LAST_LOGIN = "LastLogin";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_LAST_PASSWORD_CHANGE = "LastPasswordChange";
|
||||
|
||||
/**
|
||||
* XML_USER = "User"
|
||||
*/
|
||||
public static final String XML_PASSWORD_CHANGE_REQUESTED = "PasswordChangeRequested";
|
||||
|
||||
/**
|
||||
* XML_PRIVILEGE = "Privilege" :
|
||||
*/
|
||||
public static final String XML_PRIVILEGE = "Privilege";
|
||||
|
||||
/**
|
||||
* XML_POLICY = "Policy" :
|
||||
*/
|
||||
public static final String XML_POLICY = "Policy";
|
||||
|
||||
/**
|
||||
* XML_PARAMETERS = "Parameters" :
|
||||
*/
|
||||
public static final String XML_PARAMETERS = "Parameters";
|
||||
|
||||
/**
|
||||
* XML_PARAMETER = "Parameter" :
|
||||
*/
|
||||
public static final String XML_PARAMETER = "Parameter";
|
||||
|
||||
/**
|
||||
* XML_PROPERTIES = "Properties" :
|
||||
*/
|
||||
public static final String XML_PROPERTIES = "Properties";
|
||||
|
||||
/**
|
||||
* XML_PROPERTY = "Property" :
|
||||
*/
|
||||
public static final String XML_PROPERTY = "Property";
|
||||
|
||||
/**
|
||||
* XML_ALL_ALLOWED = "AllAllowed" :
|
||||
*/
|
||||
public static final String XML_ALL_ALLOWED = "AllAllowed";
|
||||
|
||||
/**
|
||||
* XML_DENY = "Deny" :
|
||||
*/
|
||||
public static final String XML_DENY = "Deny";
|
||||
|
||||
/**
|
||||
* XML_ALLOW = "Allow" :
|
||||
*/
|
||||
public static final String XML_ALLOW = "Allow";
|
||||
|
||||
/**
|
||||
* XML_FIRSTNAME = "Firstname" :
|
||||
*/
|
||||
public static final String XML_FIRSTNAME = "Firstname";
|
||||
|
||||
/**
|
||||
* XML_LASTNAME = "Lastname" :
|
||||
*/
|
||||
public static final String XML_LASTNAME = "Lastname";
|
||||
|
||||
/**
|
||||
* XML_STATE = "State" :
|
||||
*/
|
||||
public static final String XML_STATE = "State";
|
||||
|
||||
/**
|
||||
* XML_LOCALE = "Locale" :
|
||||
*/
|
||||
public static final String XML_LOCALE = "Locale";
|
||||
|
||||
/**
|
||||
* XML_ATTR_CLASS = "class" :
|
||||
*/
|
||||
public static final String XML_ATTR_CLASS = "class";
|
||||
|
||||
/**
|
||||
* XML_ATTR_LOGIN_TIME = "loginTime" :
|
||||
*/
|
||||
public static final String XML_ATTR_LOGIN_TIME = "loginTime";
|
||||
|
||||
/**
|
||||
* XML_ATTR_KEEP_ALIVE = "keepAlive" :
|
||||
*/
|
||||
public static final String XML_ATTR_KEEP_ALIVE = "keepAlive";
|
||||
|
||||
/**
|
||||
* XML_ATTR_LAST_ACCESS = "lastAccess" :
|
||||
*/
|
||||
public static final String XML_ATTR_LAST_ACCESS = "lastAccess";
|
||||
|
||||
/**
|
||||
* XML_ATTR_NAME = "name" :
|
||||
*/
|
||||
public static final String XML_ATTR_NAME = "name";
|
||||
|
||||
/**
|
||||
* XML_ATTR_VALUE = "value" :
|
||||
*/
|
||||
public static final String XML_ATTR_VALUE = "value";
|
||||
|
||||
/**
|
||||
* XML_ATTR_POLICY = "policy" :
|
||||
*/
|
||||
public static final String XML_ATTR_POLICY = "policy";
|
||||
|
||||
/**
|
||||
* XML_ATTR_USER_ID = "userId" :
|
||||
*/
|
||||
public static final String XML_ATTR_USER_ID = "userId";
|
||||
|
||||
/**
|
||||
* XML_ATTR_SESSION_ID = "sessionId" :
|
||||
*/
|
||||
public static final String XML_ATTR_SESSION_ID = "sessionId";
|
||||
|
||||
/**
|
||||
* XML_ATTR_SESSION_ID = "usage" :
|
||||
*/
|
||||
public static final String XML_ATTR_USAGE = "usage";
|
||||
|
||||
/**
|
||||
* XML_ATTR_USERNAME = "username" :
|
||||
*/
|
||||
public static final String XML_ATTR_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* XML_ATTR_AUTH_TOKEN = "authToken" :
|
||||
*/
|
||||
public static final String XML_ATTR_AUTH_TOKEN = "authToken";
|
||||
|
||||
/**
|
||||
* XML_ATTR_SOURCE = "source" :
|
||||
*/
|
||||
public static final String XML_ATTR_SOURCE = "source";
|
||||
|
||||
/**
|
||||
* XML_ATTR_LOCALE = "locale" :
|
||||
*/
|
||||
public static final String XML_ATTR_LOCALE = "locale";
|
||||
|
||||
/**
|
||||
* XML_ATTR_PASSWORD = "password" :
|
||||
*/
|
||||
public static final String XML_ATTR_PASSWORD = "password";
|
||||
|
||||
/**
|
||||
* XML_ATTR_SALT = "salt" :
|
||||
*/
|
||||
public static final String XML_ATTR_SALT = "salt";
|
||||
|
||||
/**
|
||||
* 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" :
|
||||
*/
|
||||
public static final String XML_PARAM_HASH_ITERATIONS = "hashIterations";
|
||||
|
||||
/**
|
||||
* XML_PARAM_HASH_ALGORITHM = "hashAlgorithm" :
|
||||
*/
|
||||
public static final String XML_PARAM_HASH_KEY_LENGTH = "hashKeyLength";
|
||||
|
||||
/**
|
||||
* XML_PARAM_USERS_FILE = "usersXmlFile" :
|
||||
*/
|
||||
public static final String XML_PARAM_USERS_FILE = "usersXmlFile";
|
||||
|
||||
/**
|
||||
* XML_PARAM_ROLES_FILE = "rolesXmlFile" :
|
||||
*/
|
||||
public static final String XML_PARAM_ROLES_FILE = "rolesXmlFile";
|
||||
|
||||
/**
|
||||
* XML_PARAM_BASE_PATH = "basePath" :
|
||||
*/
|
||||
public static final String XML_PARAM_BASE_PATH = "basePath";
|
||||
public static final String ROOT_PRIVILEGE = "Privilege";
|
||||
public static final String CONTAINER = "Container";
|
||||
public static final String POLICIES = "Policies";
|
||||
public static final String PRIVILEGES = "Privileges";
|
||||
public static final String ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles";
|
||||
public static final String ROOT_CERTIFICATES = "Certificates";
|
||||
public static final String HANDLER_USER_CHALLENGE = "UserChallengeHandler";
|
||||
public static final String HANDLER_PERSISTENCE = "PersistenceHandler";
|
||||
public static final String HANDLER_ENCRYPTION = "EncryptionHandler";
|
||||
public static final String HANDLER_PASSWORD_STRENGTH = "PasswordStrengthHandler";
|
||||
public static final String HANDLER_SSO = "SsoHandler";
|
||||
public static final String HANDLER_PRIVILEGE = "PrivilegeHandler";
|
||||
public static final String ROLES = "Roles";
|
||||
public static final String ROLE = "Role";
|
||||
public static final String USERS = "Users";
|
||||
public static final String GROUPS = "Groups";
|
||||
public static final String GROUP = "Group";
|
||||
public static final String CERTIFICATE = "Certificate";
|
||||
public static final String SESSION_DATA = "SessionData";
|
||||
public static final String USER = "User";
|
||||
public static final String HISTORY = "History";
|
||||
public static final String FIRST_LOGIN = "FirstLogin";
|
||||
public static final String LAST_LOGIN = "LastLogin";
|
||||
public static final String LAST_PASSWORD_CHANGE = "LastPasswordChange";
|
||||
public static final String PASSWORD_CHANGE_REQUESTED = "PasswordChangeRequested";
|
||||
public static final String PRIVILEGE = "Privilege";
|
||||
public static final String POLICY = "Policy";
|
||||
public static final String PARAMETERS = "Parameters";
|
||||
public static final String PARAMETER = "Parameter";
|
||||
public static final String PROPERTIES = "Properties";
|
||||
public static final String PROPERTY = "Property";
|
||||
public static final String ALL_ALLOWED = "AllAllowed";
|
||||
public static final String DENY = "Deny";
|
||||
public static final String ALLOW = "Allow";
|
||||
public static final String FIRSTNAME = "Firstname";
|
||||
public static final String LASTNAME = "Lastname";
|
||||
public static final String STATE = "State";
|
||||
public static final String LOCALE = "Locale";
|
||||
public static final String ATTR_CLASS = "class";
|
||||
public static final String ATTR_LOGIN_TIME = "loginTime";
|
||||
public static final String ATTR_KEEP_ALIVE = "keepAlive";
|
||||
public static final String ATTR_LAST_ACCESS = "lastAccess";
|
||||
public static final String ATTR_NAME = "name";
|
||||
public static final String ATTR_VALUE = "value";
|
||||
public static final String ATTR_POLICY = "policy";
|
||||
public static final String ATTR_USER_ID = "userId";
|
||||
public static final String ATTR_SESSION_ID = "sessionId";
|
||||
public static final String ATTR_USAGE = "usage";
|
||||
public static final String ATTR_USERNAME = "username";
|
||||
public static final String ATTR_AUTH_TOKEN = "authToken";
|
||||
public static final String ATTR_SOURCE = "source";
|
||||
public static final String ATTR_LOCALE = "locale";
|
||||
public static final String ATTR_PASSWORD = "password";
|
||||
public static final String ATTR_SALT = "salt";
|
||||
public static final String PARAM_HASH_ALGORITHM = "hashAlgorithm";
|
||||
public static final String PARAM_HASH_ALGORITHM_NON_SALT = "hashAlgorithmNonSalt";
|
||||
public static final String PARAM_HASH_ITERATIONS = "hashIterations";
|
||||
public static final String PARAM_HASH_KEY_LENGTH = "hashKeyLength";
|
||||
public static final String PARAM_USERS_FILE = "usersXmlFile";
|
||||
public static final String PARAM_USERS_FILE_DEF = "PrivilegeUsers.xml";
|
||||
public static final String PARAM_GROUPS_FILE = "groupsXmlFile";
|
||||
public static final String PARAM_GROUPS_FILE_DEF = "PrivilegeGroups.xml";
|
||||
public static final String PARAM_ROLES_FILE = "rolesXmlFile";
|
||||
public static final String PARAM_ROLES_FILE_DEF = "PrivilegeRoles.xml";
|
||||
public static final String PARAM_BASE_PATH = "basePath";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package li.strolch.privilege.helper;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
public class XmlHelper {
|
||||
|
||||
public static void writeStringMapElement(XMLStreamWriter xmlWriter, Map<String, String> parameterMap,
|
||||
String elementName, String valueElementName) throws XMLStreamException {
|
||||
writeStringMapElement(xmlWriter, parameterMap, elementName, valueElementName, ATTR_VALUE);
|
||||
}
|
||||
|
||||
public static void writeStringMapElement(XMLStreamWriter xmlWriter, Map<String, String> parameterMap,
|
||||
String elementName, String valueElementName, String valueAttrName) throws XMLStreamException {
|
||||
if (parameterMap == null || parameterMap.isEmpty())
|
||||
return;
|
||||
|
||||
xmlWriter.writeStartElement(elementName);
|
||||
|
||||
List<String> propertyKeys = new ArrayList<>(parameterMap.keySet());
|
||||
propertyKeys.sort(null);
|
||||
for (String propertyKey : propertyKeys) {
|
||||
xmlWriter.writeEmptyElement(valueElementName);
|
||||
xmlWriter.writeAttribute(ATTR_NAME, propertyKey);
|
||||
xmlWriter.writeAttribute(valueAttrName, parameterMap.get(propertyKey));
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
public static void writeStringList(IndentingXMLStreamWriter xmlWriter, String elementName, Set<String> values)
|
||||
throws XMLStreamException {
|
||||
List<String> denyList = new ArrayList<>(values);
|
||||
denyList.sort(null);
|
||||
for (String value : denyList) {
|
||||
writeStringElement(xmlWriter, elementName, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeStringElement(IndentingXMLStreamWriter xmlWriter, String elementName, String value)
|
||||
throws XMLStreamException {
|
||||
xmlWriter.writeStartElement(elementName);
|
||||
xmlWriter.writeCharacters(value);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
public static IndentingXMLStreamWriter openXmlStreamWriterDocument(Writer ioWriter) throws XMLStreamException {
|
||||
XMLOutputFactory factory = XMLOutputFactory.newInstance();
|
||||
IndentingXMLStreamWriter xmlWriter = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(ioWriter));
|
||||
xmlWriter.setIndent(" ");
|
||||
|
||||
// create document root
|
||||
xmlWriter.writeStartDocument(StandardCharsets.UTF_8.name(), "1.0");
|
||||
return xmlWriter;
|
||||
}
|
||||
}
|
|
@ -15,20 +15,18 @@
|
|||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||
|
||||
/**
|
||||
* The {@link Certificate} is the object a client keeps when accessing a Privilege enabled system. This object is the
|
||||
|
@ -37,7 +35,7 @@ import li.strolch.utils.helper.StringHelper;
|
|||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public final class Certificate implements Serializable {
|
||||
public final class Certificate {
|
||||
|
||||
private final Usage usage;
|
||||
private final String sessionId;
|
||||
|
@ -50,6 +48,7 @@ public final class Certificate implements Serializable {
|
|||
private final ZonedDateTime loginTime;
|
||||
private final boolean keepAlive;
|
||||
|
||||
private final Set<String> userGroups;
|
||||
private final Set<String> userRoles;
|
||||
private final Map<String, String> propertyMap;
|
||||
|
||||
|
@ -64,49 +63,28 @@ public final class Certificate implements Serializable {
|
|||
* by the {@link PrivilegeHandler}
|
||||
* </p>
|
||||
*
|
||||
* @param usage
|
||||
* the usage allowed for this certificate
|
||||
* @param sessionId
|
||||
* the users session id
|
||||
* @param username
|
||||
* the users login name
|
||||
* @param firstName
|
||||
* the users first name
|
||||
* @param lastName
|
||||
* the users last name
|
||||
* @param authToken
|
||||
* the authentication token defining the users unique session and is a private field of this certificate.
|
||||
* @param locale
|
||||
* the users {@link Locale}
|
||||
* @param userRoles
|
||||
* the user's roles
|
||||
* @param propertyMap
|
||||
* a {@link Map} containing string value pairs of properties for the logged in user. These properties can be
|
||||
* edited and can be used for the user to change settings of this session
|
||||
* @param usage the usage allowed for this certificate
|
||||
* @param sessionId the users session id
|
||||
* @param username the users login name
|
||||
* @param firstName the users first name
|
||||
* @param lastName the users last name
|
||||
* @param authToken the authentication token defining the users unique session and is a private field of this
|
||||
* certificate.
|
||||
* @param locale the users {@link Locale}
|
||||
* @param userRoles the user's roles
|
||||
* @param propertyMap a {@link Map} containing string value pairs of properties for the logged in user. These
|
||||
* properties can be edited and can be used for the user to change settings of this session
|
||||
*/
|
||||
public Certificate(Usage usage, String sessionId, String username, String firstName, String lastName,
|
||||
UserState userState, String authToken, String source, ZonedDateTime loginTime, boolean keepAlive,
|
||||
Locale locale, Set<String> userRoles, Map<String, String> propertyMap) {
|
||||
Locale locale, Set<String> userGroups, Set<String> userRoles, Map<String, String> propertyMap) {
|
||||
|
||||
// validate arguments are not null
|
||||
if (StringHelper.isEmpty(sessionId)) {
|
||||
throw new PrivilegeException("sessionId is null!");
|
||||
}
|
||||
if (StringHelper.isEmpty(username)) {
|
||||
throw new PrivilegeException("username is null!");
|
||||
}
|
||||
if (StringHelper.isEmpty(authToken)) {
|
||||
throw new PrivilegeException("authToken is null!");
|
||||
}
|
||||
if (userState == null) {
|
||||
throw new PrivilegeException("userState is null!");
|
||||
}
|
||||
if (usage == null) {
|
||||
throw new PrivilegeException("usage is null!");
|
||||
}
|
||||
if (source == null) {
|
||||
throw new PrivilegeException("source is null!");
|
||||
}
|
||||
DBC.PRE.assertNotEmpty("sessionId must not be empty", sessionId);
|
||||
DBC.PRE.assertNotEmpty("username must not be empty", username);
|
||||
DBC.PRE.assertNotEmpty("authToken must not be empty", authToken);
|
||||
DBC.PRE.assertNotNull("userState must not be empty", userState);
|
||||
DBC.PRE.assertNotNull("usage must not be empty", usage);
|
||||
DBC.PRE.assertNotNull("source must not be null", source);
|
||||
|
||||
this.usage = usage;
|
||||
this.sessionId = sessionId;
|
||||
|
@ -126,11 +104,12 @@ public final class Certificate implements Serializable {
|
|||
this.locale = locale;
|
||||
|
||||
if (propertyMap == null)
|
||||
this.propertyMap = Collections.emptyMap();
|
||||
this.propertyMap = Map.of();
|
||||
else
|
||||
this.propertyMap = Collections.unmodifiableMap(propertyMap);
|
||||
this.propertyMap = Map.copyOf(propertyMap);
|
||||
|
||||
this.userRoles = Collections.unmodifiableSet(userRoles);
|
||||
this.userGroups = Set.copyOf(userGroups);
|
||||
this.userRoles = Set.copyOf(userRoles);
|
||||
this.lastAccess = ZonedDateTime.now();
|
||||
}
|
||||
|
||||
|
@ -150,15 +129,29 @@ public final class Certificate implements Serializable {
|
|||
return this.usage;
|
||||
}
|
||||
|
||||
public Set<String> getUserGroups() {
|
||||
return this.userGroups;
|
||||
}
|
||||
|
||||
public Set<String> getUserRoles() {
|
||||
return this.userRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user of this certificate has the given group
|
||||
*
|
||||
* @param group the group to check for
|
||||
*
|
||||
* @return true if the user of this certificate has the given group
|
||||
*/
|
||||
public boolean hasGroup(String group) {
|
||||
return this.userGroups.contains(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user of this certificate has the given role
|
||||
*
|
||||
* @param role
|
||||
* the role to check for
|
||||
* @param role the role to check for
|
||||
*
|
||||
* @return true if the user of this certificate has the given role
|
||||
*/
|
||||
|
@ -178,8 +171,7 @@ public final class Certificate implements Serializable {
|
|||
/**
|
||||
* Returns the property with the given key
|
||||
*
|
||||
* @param key
|
||||
* the key for which the property is to be returned
|
||||
* @param key the key for which the property is to be returned
|
||||
*
|
||||
* @return the value of the property with the given key, or null if it does not exist
|
||||
*/
|
||||
|
@ -283,12 +275,12 @@ public final class Certificate implements Serializable {
|
|||
builder.append(", username=");
|
||||
builder.append(this.username);
|
||||
|
||||
if (StringHelper.isNotEmpty(this.firstname)) {
|
||||
if (isNotEmpty(this.firstname)) {
|
||||
builder.append(", firstname=");
|
||||
builder.append(this.firstname);
|
||||
}
|
||||
|
||||
if (StringHelper.isNotEmpty(this.lastname)) {
|
||||
if (isNotEmpty(this.lastname)) {
|
||||
builder.append(", lastname=");
|
||||
builder.append(this.lastname);
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it
|
||||
* which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a {@link
|
||||
* PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow lists
|
||||
* configured which is used to evaluate if privilege is granted to a {@link Restrictable}
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public interface IPrivilege {
|
||||
|
||||
/**
|
||||
* @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients
|
||||
*/
|
||||
PrivilegeRep asPrivilegeRep();
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @return the policy
|
||||
*/
|
||||
String getPolicy();
|
||||
|
||||
/**
|
||||
* @return the allAllowed
|
||||
*/
|
||||
boolean isAllAllowed();
|
||||
|
||||
/**
|
||||
* @return the allowList
|
||||
*/
|
||||
Set<String> getAllowList();
|
||||
|
||||
/**
|
||||
* @return the denyList
|
||||
*/
|
||||
Set<String> getDenyList();
|
||||
|
||||
/**
|
||||
* @return true if there are values in the allow list
|
||||
*/
|
||||
boolean hasAllowed();
|
||||
|
||||
/**
|
||||
* @return if the value is in the allow list
|
||||
*/
|
||||
boolean isAllowed(String value);
|
||||
|
||||
/**
|
||||
* @return true if there are values in the deny list
|
||||
*/
|
||||
boolean hasDenied();
|
||||
|
||||
/**
|
||||
* @return true if the value is in the deny list
|
||||
*/
|
||||
boolean isDenied(String value);
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link Privilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it which
|
||||
* defines the privileges a logged in user with that role has. If the {@link Privilege} has a {@link PrivilegePolicy}
|
||||
* defined, then that policy will be used for finer granularity and with the deny and allow lists configured which is
|
||||
* used to evaluate if privilege is granted to a {@link Restrictable}
|
||||
* </p>
|
||||
*
|
||||
* @param name the name of this privilege, which is unique to all privileges known in the
|
||||
* {@link PrivilegeHandler}
|
||||
* @param policy the {@link PrivilegePolicy} configured to evaluate if the privilege is granted. If null, then
|
||||
* privilege is granted
|
||||
* @param allAllowed a boolean defining if a {@link Role} with this {@link Privilege} has unrestricted access to a
|
||||
* {@link Restrictable} in which case the deny and allow lists are ignored and can be null
|
||||
* @param denyList a list of deny rules for this {@link Privilege}, can be null if all allowed
|
||||
* @param allowList a list of allow rules for this {@link Privilege}, can be null if all allowed
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public record Privilege(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
||||
|
||||
public Privilege(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
||||
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
||||
DBC.PRE.assertNotEmpty("policy must not be empty", policy);
|
||||
DBC.PRE.assertNotNull("denyList must not be null", denyList);
|
||||
DBC.PRE.assertNotNull("allowList must not be null", allowList);
|
||||
|
||||
this.name = name;
|
||||
this.allAllowed = allAllowed;
|
||||
this.policy = policy;
|
||||
this.denyList = Set.copyOf(denyList);
|
||||
this.allowList = Set.copyOf(allowList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients
|
||||
*/
|
||||
public PrivilegeRep asPrivilegeRep() {
|
||||
return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet<>(this.denyList),
|
||||
new HashSet<>(this.allowList));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getPolicy() {
|
||||
return this.policy;
|
||||
}
|
||||
|
||||
public boolean isAllAllowed() {
|
||||
return this.allAllowed;
|
||||
}
|
||||
|
||||
public Set<String> getAllowList() {
|
||||
return this.allowList;
|
||||
}
|
||||
|
||||
public Set<String> getDenyList() {
|
||||
return this.denyList;
|
||||
}
|
||||
|
||||
public boolean hasAllowed() {
|
||||
return !this.allowList.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isAllowed(String value) {
|
||||
return this.allowList.contains(value);
|
||||
}
|
||||
|
||||
public boolean hasDenied() {
|
||||
return !this.allowList.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isDenied(String value) {
|
||||
return this.denyList.contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Privilege [name=" + this.name + ", policy=" + this.policy + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Privilege other = (Privilege) obj;
|
||||
if (this.name == null)
|
||||
return other.name == null;
|
||||
return this.name.equals(other.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Privilege} from the {@link PrivilegeRep}
|
||||
*
|
||||
* @param privilegeRep the {@link PrivilegeRep} from which to create the {@link Privilege}
|
||||
*/
|
||||
public static Privilege of(PrivilegeRep privilegeRep) {
|
||||
return new Privilege(privilegeRep.getName(), privilegeRep.getPolicy(), privilegeRep.isAllAllowed(),
|
||||
privilegeRep.getDenyList(), privilegeRep.getAllowList());
|
||||
}
|
||||
}
|
|
@ -15,14 +15,16 @@
|
|||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static li.strolch.privilege.i18n.PrivilegeMessages.getString;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -36,19 +38,15 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
|||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeContext {
|
||||
public record PrivilegeContext(UserRep userRep, Certificate certificate, Map<String, Privilege> privileges,
|
||||
Map<String, PrivilegePolicy> policies) {
|
||||
|
||||
//
|
||||
// object state
|
||||
//
|
||||
|
||||
private final UserRep userRep;
|
||||
private final Certificate certificate;
|
||||
private final Map<String, IPrivilege> privileges;
|
||||
private final Map<String, PrivilegePolicy> policies;
|
||||
|
||||
public PrivilegeContext(UserRep userRep, Certificate certificate, Map<String, IPrivilege> privileges,
|
||||
public PrivilegeContext(UserRep userRep, Certificate certificate, Map<String, Privilege> privileges,
|
||||
Map<String, PrivilegePolicy> policies) {
|
||||
DBC.PRE.assertNotNull("userRep must not be null", userRep);
|
||||
DBC.PRE.assertNotNull("certificate must not be null", certificate);
|
||||
DBC.PRE.assertNotNull("privileges must not be null", privileges);
|
||||
DBC.PRE.assertNotNull("policies must not be null", policies);
|
||||
this.userRep = userRep;
|
||||
this.certificate = certificate;
|
||||
this.privileges = Map.copyOf(privileges);
|
||||
|
@ -85,35 +83,64 @@ public class PrivilegeContext {
|
|||
|
||||
public void assertHasPrivilege(String privilegeName) throws AccessDeniedException {
|
||||
if (!this.privileges.containsKey(privilegeName)) {
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"),
|
||||
userRep.getUsername(), privilegeName);
|
||||
String msg = format(getString("Privilege.noprivilege.user"), userRep.getUsername(), privilegeName);
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasGroup(String groupName) {
|
||||
return this.userRep.hasGroup(groupName);
|
||||
}
|
||||
|
||||
public boolean hasRole(String roleName) {
|
||||
return this.userRep.hasRole(roleName);
|
||||
}
|
||||
|
||||
public void assertHasRole(String roleName) throws AccessDeniedException {
|
||||
if (!this.userRep.hasRole(roleName)) {
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.role"),
|
||||
userRep.getUsername(), roleName);
|
||||
public void assertHasGroup(String groupName) throws AccessDeniedException {
|
||||
if (!this.userRep.hasGroup(groupName)) {
|
||||
String msg = format(getString("Privilege.noprivilege.group"), userRep.getUsername(), groupName);
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertHasRole(String roleName) throws AccessDeniedException {
|
||||
if (!this.userRep.hasRole(roleName)) {
|
||||
String msg = format(getString("Privilege.noprivilege.role"), userRep.getUsername(), roleName);
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertHasAnyGroup(String... groupNames) throws AccessDeniedException {
|
||||
for (String groupName : groupNames) {
|
||||
if (this.userRep.hasGroup(groupName))
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = format(getString("Privilege.noprivilege.group"), userRep.getUsername(),
|
||||
String.join(", ", groupNames));
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
|
||||
public void assertHasAnyRole(String... roleNames) throws AccessDeniedException {
|
||||
for (String roleName : roleNames) {
|
||||
if (this.userRep.hasRole(roleName))
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.role"),
|
||||
userRep.getUsername(), String.join(", ", roleNames));
|
||||
String msg = format(getString("Privilege.noprivilege.role"), userRep.getUsername(),
|
||||
String.join(", ", roleNames));
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
|
||||
public boolean hasAnyGroup(String... groupNames) throws AccessDeniedException {
|
||||
for (String groupName : groupNames) {
|
||||
if (this.userRep.hasGroup(groupName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasAnyRole(String... roleNames) throws AccessDeniedException {
|
||||
for (String roleName : roleNames) {
|
||||
if (this.userRep.hasRole(roleName))
|
||||
|
@ -123,7 +150,7 @@ public class PrivilegeContext {
|
|||
return false;
|
||||
}
|
||||
|
||||
public IPrivilege getPrivilege(String privilegeName) throws AccessDeniedException {
|
||||
public Privilege getPrivilege(String privilegeName) throws AccessDeniedException {
|
||||
assertHasPrivilege(privilegeName);
|
||||
return this.privileges.get(privilegeName);
|
||||
}
|
||||
|
@ -132,7 +159,7 @@ public class PrivilegeContext {
|
|||
PrivilegePolicy policy = this.policies.get(policyName);
|
||||
if (policy == null) {
|
||||
String msg = "The PrivilegePolicy {0} does not exist on the PrivilegeContext!";
|
||||
throw new PrivilegeException(MessageFormat.format(msg, policyName));
|
||||
throw new PrivilegeException(format(msg, policyName));
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
@ -148,15 +175,12 @@ public class PrivilegeContext {
|
|||
*
|
||||
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
||||
*
|
||||
* @param privilegeName
|
||||
* the name of the privilege to verify
|
||||
* @param privilegeValue
|
||||
* the value
|
||||
* @param privilegeName the name of the privilege to verify
|
||||
* @param privilegeValue the value
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user does not have access
|
||||
* @throws PrivilegeException
|
||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
||||
* @throws AccessDeniedException if the user does not have access
|
||||
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||
* errors
|
||||
*/
|
||||
public void validateAction(String privilegeName, String privilegeValue)
|
||||
throws PrivilegeException, AccessDeniedException {
|
||||
|
@ -168,22 +192,20 @@ public class PrivilegeContext {
|
|||
* has the privilege, then this method returns with no exception and void, if the user does not have the privilege,
|
||||
* then a {@link AccessDeniedException} is thrown.
|
||||
*
|
||||
* @param restrictable
|
||||
* the {@link Restrictable} which the user wants to access
|
||||
* @param restrictable the {@link Restrictable} which the user wants to access
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user does not have access
|
||||
* @throws PrivilegeException
|
||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
||||
* @throws AccessDeniedException if the user does not have access
|
||||
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||
* errors
|
||||
*/
|
||||
public void validateAction(Restrictable restrictable) throws PrivilegeException, AccessDeniedException {
|
||||
|
||||
// the privilege for the restrictable
|
||||
String privilegeName = restrictable.getPrivilegeName();
|
||||
IPrivilege privilege = this.privileges.get(privilegeName);
|
||||
Privilege privilege = this.privileges.get(privilegeName);
|
||||
if (privilege == null) {
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"),
|
||||
getUsername(), privilegeName, restrictable.getClass().getName(), restrictable.getPrivilegeValue());
|
||||
String msg = format(getString("Privilege.accessdenied.noprivilege"), getUsername(), privilegeName,
|
||||
restrictable.getClass().getName(), restrictable.getPrivilegeValue());
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
|
||||
|
@ -199,19 +221,18 @@ public class PrivilegeContext {
|
|||
* Validates if the user for this context has the privilege to access to the given {@link Restrictable}. Returning
|
||||
* true if the user has the privilege, and false if not
|
||||
*
|
||||
* @param restrictable
|
||||
* the {@link Restrictable} which the user wants to access
|
||||
* @param restrictable the {@link Restrictable} which the user wants to access
|
||||
*
|
||||
* @return returns true if the user has the privilege, and false if not
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
||||
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||
* errors
|
||||
*/
|
||||
public boolean hasPrivilege(Restrictable restrictable) throws PrivilegeException {
|
||||
|
||||
// the privilege for the restrictable
|
||||
String privilegeName = restrictable.getPrivilegeName();
|
||||
IPrivilege privilege = this.privileges.get(privilegeName);
|
||||
Privilege privilege = this.privileges.get(privilegeName);
|
||||
if (privilege == null)
|
||||
return false;
|
||||
|
||||
|
@ -229,15 +250,13 @@ public class PrivilegeContext {
|
|||
*
|
||||
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
||||
*
|
||||
* @param privilegeName
|
||||
* the name of the privilege to verify
|
||||
* @param privilegeValue
|
||||
* the value
|
||||
* @param privilegeName the name of the privilege to verify
|
||||
* @param privilegeValue the value
|
||||
*
|
||||
* @return returns true if the user has the privilege, and false if not
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
||||
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||
* errors
|
||||
*/
|
||||
public boolean hasPrivilege(String privilegeName, String privilegeValue) throws PrivilegeException {
|
||||
return hasPrivilege(new SimpleRestrictable(privilegeName, privilegeValue));
|
||||
|
|
|
@ -15,27 +15,25 @@
|
|||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
/**
|
||||
* To keep certain details of the {@link IPrivilege} itself hidden from remote clients and make sure instances are only
|
||||
* To keep certain details of the {@link Privilege} itself hidden from remote clients and make sure instances are only
|
||||
* edited by users with the correct privilege, this representational version is allowed to be viewed by remote clients
|
||||
* and simply wraps all public data from the {@link IPrivilege}
|
||||
* and simply wraps all public data from the {@link Privilege}
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeRep implements Serializable {
|
||||
public class PrivilegeRep {
|
||||
|
||||
private String name;
|
||||
private String policy;
|
||||
|
@ -43,48 +41,57 @@ public class PrivilegeRep implements Serializable {
|
|||
private Set<String> denyList;
|
||||
private Set<String> allowList;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param name
|
||||
* the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler}
|
||||
* @param policy
|
||||
* the {@link PrivilegePolicy} configured to evaluate if the privilege is granted
|
||||
* @param allAllowed
|
||||
* a boolean defining if a {@link Role} with this {@link IPrivilege} has unrestricted access to a {@link
|
||||
* Restrictable}
|
||||
* @param denyList
|
||||
* a list of deny rules for this {@link IPrivilege}
|
||||
* @param allowList
|
||||
* a list of allow rules for this {@link IPrivilege}
|
||||
* @param name the name of this privilege, which is unique to all privileges known in the
|
||||
* {@link PrivilegeHandler}
|
||||
* @param policy the {@link PrivilegePolicy} configured to evaluate if the privilege is granted
|
||||
* @param allAllowed a boolean defining if a {@link Role} with this {@link Privilege} has unrestricted access to a
|
||||
* {@link Restrictable}
|
||||
* @param denyList a list of deny rules for this {@link Privilege}
|
||||
* @param allowList a list of allow rules for this {@link Privilege}
|
||||
*/
|
||||
public PrivilegeRep(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
||||
this.name = trimOrEmpty(name);
|
||||
this.policy = trimOrEmpty(policy);
|
||||
this.allAllowed = allAllowed;
|
||||
this.denyList = denyList;
|
||||
this.allowList = allowList;
|
||||
setDenyList(denyList == null ? Set.of() : denyList);
|
||||
setAllowList(allowList == null ? Set.of() : allowList);
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public PrivilegeRep readOnly() {
|
||||
if (this.readOnly)
|
||||
return this;
|
||||
this.readOnly = true;
|
||||
this.denyList = Set.copyOf(this.denyList);
|
||||
this.allowList = Set.copyOf(this.allowList);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void assertNotReadonly() {
|
||||
if (this.readOnly)
|
||||
throw new IllegalStateException("Privilege is currently readOnly, to modify get a copy!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that all required fields are set
|
||||
*/
|
||||
public void validate() {
|
||||
|
||||
if (StringHelper.isEmpty(this.name)) {
|
||||
if (isEmpty(this.name))
|
||||
throw new PrivilegeException("No name defined!");
|
||||
}
|
||||
|
||||
if (StringHelper.isEmpty(this.policy)) {
|
||||
throw new PrivilegeException("policy is null!");
|
||||
}
|
||||
|
||||
if (this.denyList == null) {
|
||||
if (isEmpty(this.policy))
|
||||
throw new PrivilegeException("No policy defined!");
|
||||
if (this.denyList == null)
|
||||
throw new PrivilegeException("denyList is null");
|
||||
}
|
||||
if (this.allowList == null) {
|
||||
if (this.allowList == null)
|
||||
throw new PrivilegeException("allowList is null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,10 +102,10 @@ public class PrivilegeRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name to set
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
assertNotReadonly();
|
||||
this.name = trimOrEmpty(name);
|
||||
}
|
||||
|
||||
|
@ -110,10 +117,10 @@ public class PrivilegeRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param policy
|
||||
* the policy to set
|
||||
* @param policy the policy to set
|
||||
*/
|
||||
public void setPolicy(String policy) {
|
||||
assertNotReadonly();
|
||||
this.policy = trimOrEmpty(policy);
|
||||
}
|
||||
|
||||
|
@ -125,10 +132,10 @@ public class PrivilegeRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param allAllowed
|
||||
* the allAllowed to set
|
||||
* @param allAllowed the allAllowed to set
|
||||
*/
|
||||
public void setAllAllowed(boolean allAllowed) {
|
||||
assertNotReadonly();
|
||||
this.allAllowed = allAllowed;
|
||||
}
|
||||
|
||||
|
@ -136,30 +143,30 @@ public class PrivilegeRep implements Serializable {
|
|||
* @return the denyList
|
||||
*/
|
||||
public Set<String> getDenyList() {
|
||||
return this.denyList == null ? new HashSet<>() : this.denyList;
|
||||
return this.denyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param denyList
|
||||
* the denyList to set
|
||||
* @param denyList the denyList to set
|
||||
*/
|
||||
public void setDenyList(Set<String> denyList) {
|
||||
this.denyList = denyList.stream().map(String::trim).collect(Collectors.toSet());
|
||||
assertNotReadonly();
|
||||
this.denyList = denyList.stream().map(String::trim).collect(HashSet::new, HashSet::add, HashSet::addAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allowList
|
||||
*/
|
||||
public Set<String> getAllowList() {
|
||||
return this.allowList == null ? new HashSet<>() : this.allowList;
|
||||
return this.allowList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowList
|
||||
* the allowList to set
|
||||
* @param allowList the allowList to set
|
||||
*/
|
||||
public void setAllowList(Set<String> allowList) {
|
||||
this.allowList = allowList.stream().map(String::trim).collect(Collectors.toSet());
|
||||
assertNotReadonly();
|
||||
this.allowList = allowList.stream().map(String::trim).collect(HashSet::new, HashSet::add, HashSet::addAll);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,11 +176,8 @@ public class PrivilegeRep implements Serializable {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PrivilegeRep [name=" + this.name + ", policy=" + this.policy + ", allAllowed=" + this.allAllowed
|
||||
+ ", denyList=" + (this.denyList == null ? "null" : this.denyList.size()) + ", allowList=" + (
|
||||
this.allowList == null ?
|
||||
"null" :
|
||||
this.allowList.size()) + "]";
|
||||
return "PrivilegeRep [name=" + this.name + ", policy=" + this.policy + ", allAllowed=" + this.allAllowed +
|
||||
", denyList=" + this.denyList.size() + ", allowList=" + this.allowList.size() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -193,10 +197,13 @@ public class PrivilegeRep implements Serializable {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PrivilegeRep other = (PrivilegeRep) obj;
|
||||
if (this.name == null) {
|
||||
if (this.name == null)
|
||||
return other.name == null;
|
||||
} else
|
||||
return this.name.equals(other.name);
|
||||
return this.name.equals(other.name);
|
||||
}
|
||||
|
||||
public PrivilegeRep getCopy() {
|
||||
return new PrivilegeRep(this.name, this.policy, this.allAllowed, this.denyList, this.allowList);
|
||||
}
|
||||
|
||||
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
||||
|
|
|
@ -21,7 +21,7 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
|||
* <p>
|
||||
* Objects implementing this interface are used to grant/restrict privileges to them. A {@link PrivilegePolicy}
|
||||
* implements the logic on granting/restricting privileges for a {@link Restrictable} and the {@link
|
||||
* #getPrivilegeName()} is used to find the {@link IPrivilege} which has the associated {@link PrivilegePolicy} for
|
||||
* #getPrivilegeName()} is used to find the {@link Privilege} which has the associated {@link PrivilegePolicy} for
|
||||
* evaluating access
|
||||
* </p>
|
||||
*
|
||||
|
@ -30,9 +30,9 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
|||
public interface Restrictable {
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link IPrivilege} which is to be used to validate privileges against
|
||||
* Returns the name of the {@link Privilege} which is to be used to validate privileges against
|
||||
*
|
||||
* @return the name of the {@link IPrivilege} which is to be used to validate privileges against
|
||||
* @return the name of the {@link Privilege} which is to be used to validate privileges against
|
||||
*/
|
||||
String getPrivilegeName();
|
||||
|
||||
|
|
|
@ -15,16 +15,16 @@
|
|||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
/**
|
||||
* To keep certain details of the {@link Role} itself hidden from remote clients and make sure instances are only edited
|
||||
|
@ -33,40 +33,55 @@ import li.strolch.utils.helper.StringHelper;
|
|||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class RoleRep implements Serializable {
|
||||
public class RoleRep {
|
||||
|
||||
private String name;
|
||||
private List<PrivilegeRep> privileges;
|
||||
private Map<String, PrivilegeRep> privileges;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param name
|
||||
* the name of this role
|
||||
* @param privileges
|
||||
* the list of privileges granted to this role
|
||||
* @param name the name of this role
|
||||
* @param privileges the list of privileges granted to this role
|
||||
*/
|
||||
public RoleRep(String name, List<PrivilegeRep> privileges) {
|
||||
public RoleRep(String name, Map<String, PrivilegeRep> privileges) {
|
||||
this.name = trimOrEmpty(name);
|
||||
this.privileges = privileges;
|
||||
setPrivileges(privileges == null ? Map.of() : privileges);
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public RoleRep readOnly() {
|
||||
if (this.readOnly)
|
||||
return this;
|
||||
this.readOnly = true;
|
||||
this.privileges = Map.copyOf(this.privileges);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void assertNotReadonly() {
|
||||
if (this.readOnly)
|
||||
throw new IllegalStateException("Role is currently readOnly, to modify get a copy!");
|
||||
}
|
||||
|
||||
/**
|
||||
* validates that all required fields are set
|
||||
*/
|
||||
public void validate() {
|
||||
if (StringHelper.isEmpty(this.name))
|
||||
if (isEmpty(this.name))
|
||||
throw new PrivilegeException("name is null");
|
||||
|
||||
if (this.privileges != null && !this.privileges.isEmpty()) {
|
||||
for (PrivilegeRep privilege : this.privileges) {
|
||||
try {
|
||||
privilege.validate();
|
||||
} catch (Exception e) {
|
||||
String msg = "Privilege {0} is invalid on role {1}";
|
||||
msg = MessageFormat.format(msg, privilege.getName(), this.name);
|
||||
throw new PrivilegeException(msg, e);
|
||||
}
|
||||
for (PrivilegeRep privilege : this.privileges.values()) {
|
||||
try {
|
||||
privilege.validate();
|
||||
} catch (Exception e) {
|
||||
String msg = "Privilege {0} is invalid on role {1}";
|
||||
msg = MessageFormat.format(msg, privilege.getName(), this.name);
|
||||
throw new PrivilegeException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,30 +94,29 @@ public class RoleRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name to set
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
assertNotReadonly();
|
||||
this.name = trimOrEmpty(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the privileges assigned to this Role as a list
|
||||
*
|
||||
* @return the privileges assigned to this Role as a list
|
||||
*/
|
||||
public List<PrivilegeRep> getPrivileges() {
|
||||
return this.privileges == null ? new ArrayList<>() : this.privileges;
|
||||
public Map<String, PrivilegeRep> getPrivileges() {
|
||||
if (this.privileges == null)
|
||||
return null;
|
||||
return this.privileges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the privileges on this from a list
|
||||
*
|
||||
* @param privileges
|
||||
* the list of privileges to assign to this role
|
||||
*/
|
||||
public void setPrivileges(List<PrivilegeRep> privileges) {
|
||||
this.privileges = privileges;
|
||||
public void setPrivileges(Map<String, PrivilegeRep> privileges) {
|
||||
assertNotReadonly();
|
||||
DBC.PRE.assertNotNull("privileges must not be null!", privileges);
|
||||
this.privileges = new HashMap<>(privileges);
|
||||
}
|
||||
|
||||
public void addPrivilege(PrivilegeRep privilegeRep) {
|
||||
DBC.PRE.assertFalse(() -> "Privilege " + privilegeRep.getName() + " already on role " + this.name,
|
||||
privileges.containsKey(privilegeRep.getName()));
|
||||
this.privileges.put(privilegeRep.getName(), privilegeRep);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,8 +126,7 @@ public class RoleRep implements Serializable {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RoleRep [name=" + this.name + ", privilegeMap=" + (this.privileges == null ? "null" : this.privileges)
|
||||
+ "]";
|
||||
return "RoleRep [name=" + this.name + ", privilegeMap=" + this.privileges + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,10 +146,13 @@ public class RoleRep implements Serializable {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RoleRep other = (RoleRep) obj;
|
||||
if (this.name == null) {
|
||||
if (this.name == null)
|
||||
return other.name == null;
|
||||
} else
|
||||
return this.name.equals(other.name);
|
||||
return this.name.equals(other.name);
|
||||
}
|
||||
|
||||
public RoleRep getCopy() {
|
||||
return new RoleRep(this.name, this.privileges);
|
||||
}
|
||||
|
||||
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
||||
|
|
|
@ -26,10 +26,8 @@ public class SimpleRestrictable implements Restrictable {
|
|||
private final Object value;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of the privilege
|
||||
* @param value
|
||||
* the value allowed on the privilege
|
||||
* @param name the name of the privilege
|
||||
* @param value the value allowed on the privilege
|
||||
*/
|
||||
public SimpleRestrictable(String name, Object value) {
|
||||
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
||||
|
|
|
@ -15,20 +15,19 @@
|
|||
*/
|
||||
package li.strolch.privilege.model;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||
|
||||
/**
|
||||
* To keep certain details of the {@link User} itself hidden from remote clients and make sure instances are only edited
|
||||
|
@ -37,7 +36,7 @@ import li.strolch.utils.helper.StringHelper;
|
|||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class UserRep implements Serializable {
|
||||
public class UserRep {
|
||||
|
||||
private String userId;
|
||||
private String username;
|
||||
|
@ -45,47 +44,40 @@ public class UserRep implements Serializable {
|
|||
private String lastname;
|
||||
private UserState userState;
|
||||
private Locale locale;
|
||||
private Set<String> groups;
|
||||
private Set<String> roles;
|
||||
private Map<String, String> properties;
|
||||
|
||||
private UserHistory history;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param userId
|
||||
* the user's id
|
||||
* @param username
|
||||
* the user's login name
|
||||
* @param firstname
|
||||
* the user's first name
|
||||
* @param lastname
|
||||
* the user's last name
|
||||
* @param userState
|
||||
* the user's {@link UserState}
|
||||
* @param roles
|
||||
* the set of {@link Role}s assigned to this user
|
||||
* @param locale
|
||||
* the user's {@link Locale}
|
||||
* @param propertyMap
|
||||
* a {@link Map} containing string value pairs of properties for this user
|
||||
* @param userId the user's id
|
||||
* @param username the user's login name
|
||||
* @param firstname the user's first name
|
||||
* @param lastname the user's last name
|
||||
* @param userState the user's {@link UserState}
|
||||
* @param groups the set of {@link li.strolch.privilege.model.internal.Group}s assigned to this user
|
||||
* @param roles the set of {@link Role}s assigned to this user
|
||||
* @param locale the user's {@link Locale}
|
||||
* @param propertyMap a {@link Map} containing string value pairs of properties for this user
|
||||
*/
|
||||
public UserRep(String userId, String username, String firstname, String lastname, UserState userState,
|
||||
Set<String> roles, Locale locale, Map<String, String> propertyMap, UserHistory history) {
|
||||
Set<String> groups, Set<String> roles, Locale locale, Map<String, String> propertyMap,
|
||||
UserHistory history) {
|
||||
this.userId = trimOrEmpty(userId);
|
||||
this.username = trimOrEmpty(username);
|
||||
this.firstname = trimOrEmpty(firstname);
|
||||
this.lastname = trimOrEmpty(lastname);
|
||||
this.userState = userState;
|
||||
this.roles = roles == null ? null : roles.stream().map(String::trim).collect(Collectors.toSet());
|
||||
this.locale = locale;
|
||||
|
||||
if (propertyMap != null) {
|
||||
this.properties = new HashMap<>();
|
||||
propertyMap.forEach((key, value) -> this.properties.put(key.trim(), value.trim()));
|
||||
}
|
||||
|
||||
this.history = history;
|
||||
setGroups(groups == null ? Set.of() : groups);
|
||||
setRoles(roles == null ? Set.of() : roles);
|
||||
setProperties(properties == null ? Map.of() : properties);
|
||||
this.history = history == null ? UserHistory.EMPTY : history;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -97,30 +89,53 @@ public class UserRep implements Serializable {
|
|||
* Validates that all required fields are set
|
||||
*/
|
||||
public void validate() {
|
||||
if (isEmpty(this.userId))
|
||||
throw new PrivilegeException("userId must not be empty");
|
||||
if (isEmpty(this.username))
|
||||
throw new PrivilegeException("username must not be empty");
|
||||
|
||||
if (StringHelper.isEmpty(this.userId))
|
||||
throw new PrivilegeException("userId is null or empty");
|
||||
|
||||
if (StringHelper.isEmpty(this.username))
|
||||
throw new PrivilegeException("username is null or empty");
|
||||
|
||||
// username must be at least 2 characters in length
|
||||
if (this.username.length() < 2) {
|
||||
String msg = MessageFormat.format("The given username ''{0}'' is shorter than 2 characters", this.username);
|
||||
// username must be at least 3 characters in length
|
||||
if (this.username.length() < 3) {
|
||||
String msg = MessageFormat.format("The given username ''{0}'' is shorter than 3 characters", this.username);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
if (this.userState == null)
|
||||
throw new PrivilegeException("userState is null");
|
||||
throw new PrivilegeException("userState may not be null");
|
||||
|
||||
if (StringHelper.isEmpty(this.firstname))
|
||||
throw new PrivilegeException("firstname is null or empty");
|
||||
if (this.userState != UserState.SYSTEM) {
|
||||
if (isEmpty(this.firstname))
|
||||
throw new PrivilegeException("firstname may not be empty for non-system users");
|
||||
if (isEmpty(this.lastname))
|
||||
throw new PrivilegeException("lastname may not be empty for non-system users");
|
||||
}
|
||||
|
||||
if (StringHelper.isEmpty(this.lastname))
|
||||
throw new PrivilegeException("lastname is null or empty");
|
||||
if (this.groups == null)
|
||||
throw new PrivilegeException("groups may not be null");
|
||||
if (this.roles == null)
|
||||
throw new PrivilegeException("roles may not be null");
|
||||
|
||||
if (this.roles == null || this.roles.isEmpty())
|
||||
throw new PrivilegeException("roles is null or empty");
|
||||
if (this.groups.isEmpty() && this.roles.isEmpty())
|
||||
throw new PrivilegeException("User must have at least one group or role assigned!");
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public UserRep readOnly() {
|
||||
if (this.readOnly)
|
||||
return this;
|
||||
this.readOnly = true;
|
||||
this.groups = Set.copyOf(this.groups);
|
||||
this.roles = Set.copyOf(this.roles);
|
||||
this.properties = Map.copyOf(this.properties);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void assertNotReadonly() {
|
||||
if (this.readOnly)
|
||||
throw new IllegalStateException("User is currently readOnly, to modify get a copy!");
|
||||
}
|
||||
|
||||
public boolean isSystemUser() {
|
||||
|
@ -145,10 +160,10 @@ public class UserRep implements Serializable {
|
|||
/**
|
||||
* Set the userId
|
||||
*
|
||||
* @param userId
|
||||
* to set
|
||||
* @param userId to set
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
assertNotReadonly();
|
||||
this.userId = trimOrEmpty(userId);
|
||||
}
|
||||
|
||||
|
@ -160,10 +175,10 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* the username to set
|
||||
* @param username the username to set
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
assertNotReadonly();
|
||||
this.username = trimOrEmpty(username);
|
||||
}
|
||||
|
||||
|
@ -175,10 +190,10 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param firstname
|
||||
* the firstname to set
|
||||
* @param firstname the firstname to set
|
||||
*/
|
||||
public void setFirstname(String firstname) {
|
||||
assertNotReadonly();
|
||||
this.firstname = trimOrEmpty(firstname);
|
||||
}
|
||||
|
||||
|
@ -190,10 +205,10 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param lastname
|
||||
* the lastname to set
|
||||
* @param lastname the lastname to set
|
||||
*/
|
||||
public void setLastname(String lastname) {
|
||||
assertNotReadonly();
|
||||
this.lastname = trimOrEmpty(lastname);
|
||||
}
|
||||
|
||||
|
@ -205,13 +220,27 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param userState
|
||||
* the userState to set
|
||||
* @param userState the userState to set
|
||||
*/
|
||||
public void setUserState(UserState userState) {
|
||||
assertNotReadonly();
|
||||
this.userState = userState;
|
||||
}
|
||||
|
||||
public Set<String> getGroups() {
|
||||
return this.groups;
|
||||
}
|
||||
|
||||
public void setGroups(Set<String> groups) {
|
||||
DBC.PRE.assertNotNull("groups must not be null!", groups);
|
||||
assertNotReadonly();
|
||||
this.groups = groups.stream().map(String::trim).collect(HashSet::new, HashSet::add, HashSet::addAll);
|
||||
}
|
||||
|
||||
public boolean hasGroup(String group) {
|
||||
return this.groups.contains(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the roles
|
||||
*/
|
||||
|
@ -220,21 +249,19 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param roles
|
||||
* the roles to set
|
||||
* @param roles the roles to set
|
||||
*/
|
||||
public void setRoles(Set<String> roles) {
|
||||
this.roles = roles.stream().map(String::trim).collect(Collectors.toSet());
|
||||
DBC.PRE.assertNotNull("roles must not be null!", roles);
|
||||
assertNotReadonly();
|
||||
this.roles = roles.stream().map(String::trim).collect(HashSet::new, HashSet::add, HashSet::addAll);
|
||||
}
|
||||
|
||||
public void addRole(String role) {
|
||||
assertNotReadonly();
|
||||
this.roles.add(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this user has the given role
|
||||
*
|
||||
* @param role
|
||||
* the role to check for
|
||||
*
|
||||
* @return returns true if this user has the given role
|
||||
*/
|
||||
public boolean hasRole(String role) {
|
||||
return this.roles.contains(role);
|
||||
}
|
||||
|
@ -247,10 +274,10 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param locale
|
||||
* the locale to set
|
||||
* @param locale the locale to set
|
||||
*/
|
||||
public void setLocale(Locale locale) {
|
||||
assertNotReadonly();
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
@ -260,18 +287,15 @@ public class UserRep implements Serializable {
|
|||
* @return the user history
|
||||
*/
|
||||
public UserHistory getHistory() {
|
||||
if (this.history == null)
|
||||
return new UserHistory();
|
||||
return this.history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the the given property exists
|
||||
* Returns true if the given property exists
|
||||
*
|
||||
* @param key
|
||||
* the property key to check
|
||||
* @param key the property key to check
|
||||
*
|
||||
* @return true if the the given property exists
|
||||
* @return true if the given property exists
|
||||
*/
|
||||
public boolean hasProperty(String key) {
|
||||
return this.properties.containsKey(key);
|
||||
|
@ -280,40 +304,41 @@ public class UserRep implements Serializable {
|
|||
/**
|
||||
* Returns the property with the given key
|
||||
*
|
||||
* @param key
|
||||
* the key for which the property is to be returned
|
||||
* @param key 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
|
||||
*/
|
||||
public String getProperty(String key) {
|
||||
if (this.properties == null)
|
||||
return null;
|
||||
return this.properties.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property with the key to the value
|
||||
*
|
||||
* @param key
|
||||
* the key of the property to set
|
||||
* @param value
|
||||
* the value of the property to set
|
||||
* @param key the key of the property to set
|
||||
* @param value the value of the property to set
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
if (this.properties == null)
|
||||
this.properties = new HashMap<>(1);
|
||||
DBC.PRE.assertNotEmpty("key must not be empty!", key);
|
||||
DBC.PRE.assertNotEmpty("value must not be empty!", value);
|
||||
assertNotReadonly();
|
||||
this.properties.put(key.trim(), value.trim());
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, String> properties) {
|
||||
DBC.PRE.assertNotNull("properties must not be null!", properties);
|
||||
assertNotReadonly();
|
||||
this.properties = new HashMap<>();
|
||||
properties.forEach((key, value) -> this.properties.put(key.trim(), value.trim()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of keys of all properties
|
||||
*
|
||||
* @return the {@link Set} of keys of all properties
|
||||
*/
|
||||
public Set<String> getPropertyKeySet() {
|
||||
if (this.properties == null)
|
||||
return new HashSet<>();
|
||||
return new HashSet<>(this.properties.keySet());
|
||||
return this.properties.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -322,9 +347,7 @@ public class UserRep implements Serializable {
|
|||
* @return the map of properties
|
||||
*/
|
||||
public Map<String, String> getProperties() {
|
||||
if (this.properties == null)
|
||||
return new HashMap<>();
|
||||
return new HashMap<>(this.properties);
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -361,9 +384,9 @@ public class UserRep implements Serializable {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserRep [userId=" + this.userId + ", username=" + this.username + ", firstname=" + this.firstname
|
||||
+ ", lastname=" + this.lastname + ", userState=" + this.userState + ", locale=" + this.locale
|
||||
+ ", roles=" + this.roles + "]";
|
||||
return "UserRep [userId=" + this.userId + ", username=" + this.username + ", firstname=" + this.firstname +
|
||||
", lastname=" + this.lastname + ", userState=" + this.userState + ", locale=" + this.locale +
|
||||
", roles=" + this.roles + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -390,12 +413,8 @@ public class UserRep implements Serializable {
|
|||
}
|
||||
|
||||
public UserRep getCopy() {
|
||||
|
||||
Set<String> roles = new HashSet<>(this.roles);
|
||||
Map<String, String> propertyMap = this.properties == null ? null : new HashMap<>(this.properties);
|
||||
|
||||
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, roles,
|
||||
this.locale, propertyMap, this.history == null ? new UserHistory() : this.history.getClone());
|
||||
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, this.groups,
|
||||
this.roles, this.locale, this.properties, this.history);
|
||||
}
|
||||
|
||||
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
|
||||
/**
|
||||
* This entity represents a group with which {@link User Users} can be associated. This allows to put roles and
|
||||
* properties which are always duplicated on users on to the group, and the User is then in the group, eliminating
|
||||
* duplication.
|
||||
*/
|
||||
public record Group(String name, Set<String> roles, Map<String, String> propertyMap) {
|
||||
public Group(String name, Set<String> roles, Map<String, String> propertyMap) {
|
||||
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
||||
DBC.PRE.assertNotNull("roles must not be null", roles);
|
||||
DBC.PRE.assertNotNull("propertyMap must not be null", propertyMap);
|
||||
this.name = name;
|
||||
this.roles = Set.copyOf(roles);
|
||||
this.propertyMap = Map.copyOf(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this group has the specified role
|
||||
*
|
||||
* @param role the name of the {@link Role} to check for
|
||||
*
|
||||
* @return true if this group has the specified role
|
||||
*/
|
||||
public boolean hasRole(String role) {
|
||||
return this.roles.contains(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property with the given key
|
||||
*
|
||||
* @param key 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
|
||||
*/
|
||||
public String getProperty(String key) {
|
||||
return this.propertyMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of keys of all properties
|
||||
*
|
||||
* @return the {@link Set} of keys of all properties
|
||||
*/
|
||||
public Set<String> getPropertyKeySet() {
|
||||
return this.propertyMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map of properties
|
||||
*
|
||||
* @return the map of properties
|
||||
*/
|
||||
public Map<String, String> getProperties() {
|
||||
return this.propertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property {@link PrivilegeConstants#REALM}
|
||||
*
|
||||
* @return the value of the property {@link PrivilegeConstants#REALM}
|
||||
*/
|
||||
public String getRealm() {
|
||||
return getProperty(REALM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property {@link PrivilegeConstants#ORGANISATION}
|
||||
*
|
||||
* @return the value of the property {@link PrivilegeConstants#ORGANISATION}
|
||||
*/
|
||||
public String getOrganisation() {
|
||||
return getProperty(ORGANISATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property {@link PrivilegeConstants#LOCATION}
|
||||
*
|
||||
* @return the value of the property {@link PrivilegeConstants#LOCATION}
|
||||
*/
|
||||
public String getLocation() {
|
||||
return getProperty(LOCATION);
|
||||
}
|
||||
}
|
|
@ -2,48 +2,33 @@ package li.strolch.privilege.model.internal;
|
|||
|
||||
import static li.strolch.utils.helper.StringHelper.*;
|
||||
|
||||
public class PasswordCrypt {
|
||||
public record PasswordCrypt(byte[] password, byte[] salt, String hashAlgorithm, int hashIterations, int hashKeyLength) {
|
||||
|
||||
private final byte[] password;
|
||||
private final byte[] salt;
|
||||
private final String hashAlgorithm;
|
||||
private final int hashIterations;
|
||||
private final int hashKeyLength;
|
||||
|
||||
public PasswordCrypt(byte[] password, byte[] salt) {
|
||||
this.password = password;
|
||||
this.salt = salt;
|
||||
this.hashAlgorithm = null;
|
||||
this.hashIterations = -1;
|
||||
this.hashKeyLength = -1;
|
||||
@Override
|
||||
public String toString() {
|
||||
return buildPasswordString();
|
||||
}
|
||||
|
||||
public PasswordCrypt(byte[] password, byte[] salt, String hashAlgorithm, int hashIterations, int hashKeyLength) {
|
||||
this.password = password;
|
||||
this.salt = salt;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.hashIterations = hashIterations;
|
||||
this.hashKeyLength = hashKeyLength;
|
||||
public String buildPasswordString() {
|
||||
if (this.password == null || this.salt == null || this.hashAlgorithm == null || this.hashIterations == -1 ||
|
||||
this.hashKeyLength == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return buildPasswordString(this.hashAlgorithm, this.hashIterations, this.hashKeyLength, this.salt,
|
||||
this.password);
|
||||
}
|
||||
|
||||
public byte[] getPassword() {
|
||||
return password;
|
||||
public static String buildPasswordString(String hashAlgorithm, int hashIterations, int hashKeyLength, byte[] salt,
|
||||
byte[] passwordArr) {
|
||||
String algo = hashAlgorithm + "," + hashIterations + "," + hashKeyLength;
|
||||
String hash = toHexString(salt);
|
||||
String password = toHexString(passwordArr);
|
||||
return "$" + algo + "$" + hash + "$" + password;
|
||||
}
|
||||
|
||||
public byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public String getHashAlgorithm() {
|
||||
return hashAlgorithm;
|
||||
}
|
||||
|
||||
public int getHashIterations() {
|
||||
return hashIterations;
|
||||
}
|
||||
|
||||
public int getHashKeyLength() {
|
||||
return hashKeyLength;
|
||||
public static PasswordCrypt of(byte[] password, byte[] salt) {
|
||||
return new PasswordCrypt(password, salt, null, -1, -1);
|
||||
}
|
||||
|
||||
public static PasswordCrypt parse(String passwordS, String saltS) {
|
||||
|
@ -55,14 +40,14 @@ public class PasswordCrypt {
|
|||
salt = fromHexString(saltS.trim());
|
||||
|
||||
if (isEmpty(passwordS))
|
||||
return new PasswordCrypt(null, salt);
|
||||
return PasswordCrypt.of(null, salt);
|
||||
|
||||
passwordS = passwordS.trim();
|
||||
|
||||
byte[] password;
|
||||
if (!passwordS.startsWith("$")) {
|
||||
password = fromHexString(passwordS);
|
||||
return new PasswordCrypt(password, salt);
|
||||
return PasswordCrypt.of(password, salt);
|
||||
}
|
||||
|
||||
String[] parts = passwordS.split("\\$");
|
||||
|
@ -86,28 +71,4 @@ public class PasswordCrypt {
|
|||
|
||||
return new PasswordCrypt(password, salt, hashAlgorithm, hashIterations, hashKeyLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return buildPasswordString();
|
||||
}
|
||||
|
||||
public String buildPasswordString() {
|
||||
if (this.password == null || this.salt == null || this.hashAlgorithm == null || this.hashIterations == -1 ||
|
||||
this.hashKeyLength == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return buildPasswordString(getHashAlgorithm(), getHashIterations(), getHashKeyLength(), getSalt(),
|
||||
getPassword());
|
||||
|
||||
}
|
||||
|
||||
public static String buildPasswordString(String hashAlgorithm, int hashIterations, int hashKeyLength, byte[] salt,
|
||||
byte[] passwordArr) {
|
||||
String algo = hashAlgorithm + "," + hashIterations + "," + hashKeyLength;
|
||||
String hash = toHexString(salt);
|
||||
String password = toHexString(passwordArr);
|
||||
return "$" + algo + "$" + hash + "$" + password;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.PrivilegeRep;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it
|
||||
* which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a {@link
|
||||
* PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow lists
|
||||
* configured which is used to evaluate if privilege is granted to a {@link Restrictable}
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* {@link IPrivilege}s have allow and deny rules which the configured {@link PrivilegeHandler} uses to
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: This is an internal object which is not to be serialized or passed to clients, {@link PrivilegeRep}s are used
|
||||
* for that
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public final class PrivilegeImpl implements IPrivilege {
|
||||
|
||||
private final String name;
|
||||
private final String policy;
|
||||
private final boolean allAllowed;
|
||||
private final Set<String> denyList;
|
||||
private final Set<String> allowList;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param name
|
||||
* the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler}
|
||||
* @param policy
|
||||
* the {@link PrivilegePolicy} configured to evaluate if the privilege is granted. If null, then privilege is
|
||||
* granted
|
||||
* @param allAllowed
|
||||
* a boolean defining if a {@link Role} with this {@link PrivilegeImpl} has unrestricted access to a {@link
|
||||
* Restrictable} in which case the deny and allow lists are ignored and can be null
|
||||
* @param denyList
|
||||
* a list of deny rules for this {@link PrivilegeImpl}, can be null if all allowed
|
||||
* @param allowList
|
||||
* a list of allow rules for this {@link PrivilegeImpl}, can be null if all allowed
|
||||
*/
|
||||
public PrivilegeImpl(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
||||
|
||||
if (StringHelper.isEmpty(name)) {
|
||||
throw new PrivilegeException("No name defined!");
|
||||
}
|
||||
if (StringHelper.isEmpty(policy)) {
|
||||
throw new PrivilegeException(
|
||||
MessageFormat.format("Policy may not be empty for Privilege {0}!", name));
|
||||
}
|
||||
if (denyList == null) {
|
||||
throw new PrivilegeException(
|
||||
MessageFormat.format("denyList is null for Privilege {0}!", name));
|
||||
}
|
||||
if (allowList == null) {
|
||||
throw new PrivilegeException(
|
||||
MessageFormat.format("allowList is null for Privilege {0}!", name));
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.allAllowed = allAllowed;
|
||||
this.policy = policy;
|
||||
this.denyList = Collections.unmodifiableSet(denyList);
|
||||
this.allowList = Collections.unmodifiableSet(allowList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link PrivilegeImpl} from the {@link PrivilegeRep}
|
||||
*
|
||||
* @param privilegeRep
|
||||
* the {@link PrivilegeRep} from which to create the {@link PrivilegeImpl}
|
||||
*/
|
||||
public PrivilegeImpl(PrivilegeRep privilegeRep) {
|
||||
this(privilegeRep.getName(), privilegeRep.getPolicy(), privilegeRep.isAllAllowed(), privilegeRep.getDenyList(),
|
||||
privilegeRep.getAllowList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients
|
||||
*/
|
||||
@Override
|
||||
public PrivilegeRep asPrivilegeRep() {
|
||||
return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet<>(this.denyList),
|
||||
new HashSet<>(this.allowList));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the policy
|
||||
*/
|
||||
@Override
|
||||
public String getPolicy() {
|
||||
return this.policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allAllowed
|
||||
*/
|
||||
@Override
|
||||
public boolean isAllAllowed() {
|
||||
return this.allAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allowList
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getAllowList() {
|
||||
return this.allowList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the denyList
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getDenyList() {
|
||||
return this.denyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there are values in the allow list
|
||||
*/
|
||||
@Override
|
||||
public boolean hasAllowed() {
|
||||
return !this.allowList.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the value is in the allow list
|
||||
*/
|
||||
@Override
|
||||
public boolean isAllowed(String value) {
|
||||
return this.allowList.contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there are values in the deny list
|
||||
*/
|
||||
@Override
|
||||
public boolean hasDenied() {
|
||||
return !this.allowList.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the value is in the deny list
|
||||
*/
|
||||
@Override
|
||||
public boolean isDenied(String value) {
|
||||
return this.denyList.contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this object displaying its concrete type and its values
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Privilege [name=" + this.name + ", policy=" + this.policy + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PrivilegeImpl other = (PrivilegeImpl) obj;
|
||||
if (this.name == null) {
|
||||
return other.name == null;
|
||||
} else
|
||||
return this.name.equals(other.name);
|
||||
}
|
||||
}
|
|
@ -15,14 +15,17 @@
|
|||
*/
|
||||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeRep;
|
||||
import li.strolch.privilege.model.RoleRep;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -37,57 +40,32 @@ import li.strolch.utils.helper.StringHelper;
|
|||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public final class Role {
|
||||
|
||||
private final String name;
|
||||
private final Map<String, IPrivilege> privilegeMap;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param name
|
||||
* the name of the role
|
||||
* @param privilegeMap
|
||||
* a map of {@link IPrivilege}s granted to this role
|
||||
*/
|
||||
public Role(String name, Map<String, IPrivilege> privilegeMap) {
|
||||
|
||||
if (StringHelper.isEmpty(name)) {
|
||||
throw new PrivilegeException("No name defined!");
|
||||
}
|
||||
if (privilegeMap == null) {
|
||||
throw new PrivilegeException("No privileges defined!");
|
||||
}
|
||||
public record Role(String name, Map<String, Privilege> privilegeMap) {
|
||||
|
||||
public Role(String name, Map<String, Privilege> privilegeMap) {
|
||||
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
||||
DBC.PRE.assertNotNull("privilegeMap must not be null", privilegeMap);
|
||||
this.name = name;
|
||||
this.privilegeMap = Collections.unmodifiableMap(privilegeMap);
|
||||
this.privilegeMap = Map.copyOf(privilegeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct {@link Role} from its representation {@link RoleRep}
|
||||
*
|
||||
* @param roleRep
|
||||
* the representation from which to create the {@link Role}
|
||||
* @param roleRep the representation from which to create the {@link Role}
|
||||
*/
|
||||
public Role(RoleRep roleRep) {
|
||||
|
||||
public static Role of(RoleRep roleRep) {
|
||||
String name = roleRep.getName();
|
||||
if (StringHelper.isEmpty(name)) {
|
||||
if (isEmpty(name))
|
||||
throw new PrivilegeException("No name defined!");
|
||||
}
|
||||
|
||||
if (roleRep.getPrivileges() == null) {
|
||||
if (roleRep.getPrivileges() == null)
|
||||
throw new PrivilegeException("Privileges may not be null!");
|
||||
}
|
||||
|
||||
// build privileges from rep
|
||||
Map<String, IPrivilege> privilegeMap = new HashMap<>(roleRep.getPrivileges().size());
|
||||
for (PrivilegeRep privilege : roleRep.getPrivileges()) {
|
||||
privilegeMap.put(privilege.getName(), new PrivilegeImpl(privilege));
|
||||
}
|
||||
Map<String, Privilege> privilegeMap = new HashMap<>(roleRep.getPrivileges().size());
|
||||
roleRep.getPrivileges().values().forEach(p -> privilegeMap.put(p.getName(), Privilege.of(p)));
|
||||
|
||||
this.name = name;
|
||||
this.privilegeMap = Collections.unmodifiableMap(privilegeMap);
|
||||
return new Role(name, privilegeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,30 +76,29 @@ public final class Role {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of names for the currently stored {@link IPrivilege Privileges}
|
||||
* Returns the {@link Set} of names for the currently stored {@link Privilege Privileges}
|
||||
*
|
||||
* @return the {@link Set} of names for the currently stored {@link IPrivilege Privileges}
|
||||
* @return the {@link Set} of names for the currently stored {@link Privilege Privileges}
|
||||
*/
|
||||
public Set<String> getPrivilegeNames() {
|
||||
return this.privilegeMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link IPrivilege} for the given name, null if it does not exist
|
||||
* Returns the {@link Privilege} for the given name, null if it does not exist
|
||||
*
|
||||
* @return the {@link IPrivilege} for the given name, null if it does not exist
|
||||
* @return the {@link Privilege} for the given name, null if it does not exist
|
||||
*/
|
||||
public IPrivilege getPrivilege(String name) {
|
||||
public Privilege getPrivilege(String name) {
|
||||
return this.privilegeMap.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this {@link Role} has the {@link IPrivilege} with the given name
|
||||
* Determines if this {@link Role} has the {@link Privilege} with the given name
|
||||
*
|
||||
* @param name
|
||||
* the name of the {@link IPrivilege}
|
||||
* @param name the name of the {@link Privilege}
|
||||
*
|
||||
* @return true if this {@link Role} has the {@link IPrivilege} with the given name
|
||||
* @return true if this {@link Role} has the {@link Privilege} with the given name
|
||||
*/
|
||||
public boolean hasPrivilege(String name) {
|
||||
return this.privilegeMap.containsKey(name);
|
||||
|
@ -131,10 +108,8 @@ public final class Role {
|
|||
* @return a {@link RoleRep} which is a representation of this object used to serialize and view on clients
|
||||
*/
|
||||
public RoleRep asRoleRep() {
|
||||
List<PrivilegeRep> privileges = new ArrayList<>();
|
||||
for (Entry<String, IPrivilege> entry : this.privilegeMap.entrySet()) {
|
||||
privileges.add(entry.getValue().asPrivilegeRep());
|
||||
}
|
||||
Map<String, PrivilegeRep> privileges = new HashMap<>();
|
||||
this.privilegeMap.values().forEach(p -> privileges.put(p.getName(), p.asPrivilegeRep()));
|
||||
return new RoleRep(this.name, privileges);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,14 @@
|
|||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.UserRep;
|
||||
import li.strolch.privilege.model.UserState;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
|
||||
|
@ -34,59 +36,36 @@ import static li.strolch.privilege.base.PrivilegeConstants.*;
|
|||
* that
|
||||
* </p>
|
||||
*
|
||||
* @param userId the user's id
|
||||
* @param username the user's login name
|
||||
* @param passwordCrypt the {@link PasswordCrypt} containing user's password information
|
||||
* @param firstname the user's first name
|
||||
* @param lastname the user's lastname
|
||||
* @param userState the user's {@link UserState}
|
||||
* @param groups the set of {@link Group}s assigned to this user
|
||||
* @param roles the set of {@link Role}s assigned to this user
|
||||
* @param locale the user's {@link Locale}
|
||||
* @param propertyMap a {@link Map} containing string value pairs of properties for this user
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public final class User {
|
||||
public record User(String userId, String username, PasswordCrypt passwordCrypt, String firstname, String lastname,
|
||||
UserState userState, Set<String> groups, Set<String> roles, Locale locale,
|
||||
Map<String, String> propertyMap, boolean passwordChangeRequested, UserHistory history) {
|
||||
|
||||
private final String userId;
|
||||
|
||||
private final String username;
|
||||
private final PasswordCrypt passwordCrypt;
|
||||
|
||||
private final String firstname;
|
||||
private final String lastname;
|
||||
|
||||
private final Set<String> roles;
|
||||
|
||||
private final UserState userState;
|
||||
private final Map<String, String> propertyMap;
|
||||
private final Locale locale;
|
||||
|
||||
private final boolean passwordChangeRequested;
|
||||
private final UserHistory history;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param userId the user's id
|
||||
* @param username the user's login name
|
||||
* @param passwordCrypt the {@link PasswordCrypt} containing user's password information
|
||||
* @param firstname the user's first name
|
||||
* @param lastname the user's lastname
|
||||
* @param userState the user's {@link UserState}
|
||||
* @param roles the set of {@link Role}s assigned to this user
|
||||
* @param locale the user's {@link Locale}
|
||||
* @param propertyMap a {@link Map} containing string value pairs of properties for this user
|
||||
*/
|
||||
public User(String userId, String username, PasswordCrypt passwordCrypt, String firstname, String lastname,
|
||||
UserState userState, Set<String> roles, Locale locale, Map<String, String> propertyMap,
|
||||
UserState userState, Set<String> groups, Set<String> roles, Locale locale, Map<String, String> propertyMap,
|
||||
boolean passwordChangeRequested, UserHistory history) {
|
||||
|
||||
if (StringHelper.isEmpty(userId))
|
||||
throw new PrivilegeException("No UserId defined!");
|
||||
if (userState == null)
|
||||
throw new PrivilegeException("No userState defined!");
|
||||
if (StringHelper.isEmpty(username))
|
||||
throw new PrivilegeException("No username defined!");
|
||||
if (userState != UserState.SYSTEM) {
|
||||
if (StringHelper.isEmpty(lastname))
|
||||
throw new PrivilegeException("No lastname defined!");
|
||||
if (StringHelper.isEmpty(firstname))
|
||||
throw new PrivilegeException("No firstname defined!");
|
||||
}
|
||||
DBC.PRE.assertNotEmpty("userId must not be empty", userId);
|
||||
DBC.PRE.assertNotEmpty("username must not be empty", username);
|
||||
DBC.PRE.assertNotNull("userState must not be null", userState);
|
||||
DBC.PRE.assertNotNull("history must not be null", history);
|
||||
|
||||
if (history == null)
|
||||
throw new PrivilegeException("History must not be null!");
|
||||
if (userState != UserState.SYSTEM) {
|
||||
DBC.PRE.assertNotEmpty("lastname must not be empty when not system user!", username);
|
||||
DBC.PRE.assertNotEmpty("firstname must not be empty when not system user!", firstname);
|
||||
}
|
||||
|
||||
// passwordCrypt may be null, meaning not able to login
|
||||
// roles may be null, meaning not able to login and must be added later
|
||||
|
@ -103,35 +82,19 @@ public final class User {
|
|||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
|
||||
if (roles == null)
|
||||
this.roles = Collections.emptySet();
|
||||
else
|
||||
this.roles = Set.copyOf(roles);
|
||||
|
||||
if (locale == null)
|
||||
this.locale = Locale.getDefault();
|
||||
else
|
||||
this.locale = locale;
|
||||
|
||||
if (propertyMap == null)
|
||||
this.propertyMap = Collections.emptyMap();
|
||||
else
|
||||
this.propertyMap = Map.copyOf(propertyMap);
|
||||
this.groups = groups == null ? Set.of() : Set.copyOf(groups);
|
||||
this.roles = roles == null ? Set.of() : Set.copyOf(roles);
|
||||
this.locale = locale == null ? Locale.getDefault() : locale;
|
||||
this.propertyMap = propertyMap == null ? Map.of() : Map.copyOf(propertyMap);
|
||||
|
||||
this.passwordChangeRequested = passwordChangeRequested;
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userId
|
||||
*/
|
||||
public String getUserId() {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
@ -145,48 +108,34 @@ public final class User {
|
|||
return this.passwordCrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the first name
|
||||
*/
|
||||
public String getFirstname() {
|
||||
return this.firstname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the last name
|
||||
*/
|
||||
public String getLastname() {
|
||||
return this.lastname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userState
|
||||
*/
|
||||
public UserState getUserState() {
|
||||
return this.userState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the roles
|
||||
*/
|
||||
public Set<String> getGroups() {
|
||||
return this.groups;
|
||||
}
|
||||
|
||||
public Set<String> getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this user has the specified role
|
||||
*
|
||||
* @param role the name of the {@link Role} to check for
|
||||
*
|
||||
* @return true if the this user has the specified role
|
||||
*/
|
||||
public boolean hasGroup(String group) {
|
||||
return this.groups.contains(group);
|
||||
}
|
||||
|
||||
public boolean hasRole(String role) {
|
||||
return this.roles.contains(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the locale
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
@ -195,11 +144,6 @@ public final class User {
|
|||
return this.passwordChangeRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the History object
|
||||
*
|
||||
* @return the History object
|
||||
*/
|
||||
public UserHistory getHistory() {
|
||||
return this.history;
|
||||
}
|
||||
|
@ -282,8 +226,8 @@ public final class User {
|
|||
* @return a {@link UserRep} which is a representation of this object used to serialize and view on clients
|
||||
*/
|
||||
public UserRep asUserRep() {
|
||||
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState,
|
||||
new HashSet<>(this.roles), this.locale, new HashMap<>(this.propertyMap), this.history.getClone());
|
||||
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, this.groups,
|
||||
this.roles, this.locale, new HashMap<>(this.propertyMap), this.history);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,9 +259,13 @@ public final class User {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
User other = (User) obj;
|
||||
if (this.userId == null) {
|
||||
if (this.userId == null)
|
||||
return other.userId == null;
|
||||
} else
|
||||
return this.userId.equals(other.userId);
|
||||
return this.userId.equals(other.userId);
|
||||
}
|
||||
|
||||
public User withHistory(UserHistory history) {
|
||||
return new User(this.userId, this.username, this.passwordCrypt, this.firstname, this.lastname, this.userState,
|
||||
this.groups, this.roles, this.locale, this.propertyMap, this.passwordChangeRequested, history);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import li.strolch.privilege.model.Usage;
|
||||
|
||||
public class UserChallenge {
|
||||
public final class UserChallenge {
|
||||
private final User user;
|
||||
private final String challenge;
|
||||
private final String source;
|
||||
|
@ -13,6 +14,10 @@ public class UserChallenge {
|
|||
private boolean fulfilled;
|
||||
|
||||
public UserChallenge(Usage usage, User user, String challenge, String source) {
|
||||
DBC.PRE.assertNotNull("usage may not be null", usage);
|
||||
DBC.PRE.assertNotNull("user may not be null", user);
|
||||
DBC.PRE.assertNotNull("challenge may not be empty", challenge);
|
||||
DBC.PRE.assertNotNull("source may not be empty", source);
|
||||
this.usage = usage;
|
||||
this.user = user;
|
||||
this.challenge = challenge;
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
package li.strolch.privilege.model.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import static li.strolch.utils.iso8601.ISO8601.EMPTY_VALUE_ZONED_DATE;
|
||||
|
||||
public class UserHistory implements Serializable {
|
||||
public record UserHistory(ZonedDateTime firstLogin, ZonedDateTime lastLogin, ZonedDateTime lastPasswordChange) {
|
||||
|
||||
private ZonedDateTime firstLogin;
|
||||
private ZonedDateTime lastLogin;
|
||||
private ZonedDateTime lastPasswordChange;
|
||||
|
||||
public UserHistory() {
|
||||
this.firstLogin = ISO8601.EMPTY_VALUE_ZONED_DATE;
|
||||
this.lastLogin = ISO8601.EMPTY_VALUE_ZONED_DATE;
|
||||
this.lastPasswordChange = ISO8601.EMPTY_VALUE_ZONED_DATE;
|
||||
}
|
||||
public static final UserHistory EMPTY = new UserHistory(EMPTY_VALUE_ZONED_DATE, EMPTY_VALUE_ZONED_DATE,
|
||||
EMPTY_VALUE_ZONED_DATE);
|
||||
|
||||
public ZonedDateTime getFirstLogin() {
|
||||
return this.firstLogin;
|
||||
}
|
||||
|
||||
public boolean isFirstLoginEmpty() {
|
||||
return this.firstLogin.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public void setFirstLogin(ZonedDateTime firstLogin) {
|
||||
this.firstLogin = firstLogin;
|
||||
return this.firstLogin.equals(EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public ZonedDateTime getLastLogin() {
|
||||
|
@ -34,11 +22,7 @@ public class UserHistory implements Serializable {
|
|||
}
|
||||
|
||||
public boolean isLastLoginEmpty() {
|
||||
return this.lastLogin.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public void setLastLogin(ZonedDateTime lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
return this.lastLogin.equals(EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public ZonedDateTime getLastPasswordChange() {
|
||||
|
@ -46,22 +30,26 @@ public class UserHistory implements Serializable {
|
|||
}
|
||||
|
||||
public boolean isLastPasswordChangeEmpty() {
|
||||
return this.lastPasswordChange.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public void setLastPasswordChange(ZonedDateTime lastPasswordChange) {
|
||||
this.lastPasswordChange = lastPasswordChange;
|
||||
return this.lastPasswordChange.equals(EMPTY_VALUE_ZONED_DATE);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return isFirstLoginEmpty() && isLastLoginEmpty() && isLastPasswordChangeEmpty();
|
||||
}
|
||||
|
||||
public UserHistory getClone() {
|
||||
UserHistory clone = new UserHistory();
|
||||
clone.firstLogin = this.firstLogin;
|
||||
clone.lastLogin = this.lastLogin;
|
||||
clone.lastPasswordChange = this.lastPasswordChange;
|
||||
return clone;
|
||||
public UserHistory withFirstLogin(ZonedDateTime firstLogin) {
|
||||
return new UserHistory(firstLogin, this.lastLogin, lastPasswordChange);
|
||||
}
|
||||
|
||||
public UserHistory withLastLogin(ZonedDateTime lastLogin) {
|
||||
return new UserHistory(this.firstLogin, lastLogin, this.lastPasswordChange);
|
||||
}
|
||||
|
||||
public UserHistory withLogin(ZonedDateTime lastLogin) {
|
||||
return new UserHistory(isFirstLoginEmpty() ? lastLogin : this.firstLogin, lastLogin, this.lastPasswordChange);
|
||||
}
|
||||
|
||||
public UserHistory withLastPasswordChange(ZonedDateTime lastPasswordChange) {
|
||||
return new UserHistory(this.firstLogin, this.lastLogin, lastPasswordChange);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.text.MessageFormat;
|
|||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
|
@ -38,10 +38,10 @@ public class DefaultPrivilege implements PrivilegePolicy {
|
|||
/**
|
||||
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
|
||||
*
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, IPrivilege, Restrictable)
|
||||
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Privilege, Restrictable)
|
||||
*/
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
|
||||
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
||||
|
@ -54,7 +54,7 @@ public class DefaultPrivilege implements PrivilegePolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable) {
|
||||
|
||||
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class DefaultPrivilege implements PrivilegePolicy {
|
|||
return checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue, false);
|
||||
}
|
||||
|
||||
private String validatePrivilegeValue(IPrivilege privilege, Restrictable restrictable) {
|
||||
private String validatePrivilegeValue(Privilege privilege, Restrictable restrictable) {
|
||||
PrivilegePolicyHelper.preValidate(privilege, restrictable);
|
||||
|
||||
// get the value on which the action is to be performed
|
||||
|
|
|
@ -17,7 +17,7 @@ package li.strolch.privilege.policy;
|
|||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
|
@ -26,7 +26,7 @@ import li.strolch.privilege.model.internal.User;
|
|||
/**
|
||||
* <p>
|
||||
* {@link PrivilegePolicy} implements logic to determine if a {@link User} which has the given {@link Role} and the
|
||||
* given {@link IPrivilege} has access to the given {@link Restrictable}
|
||||
* given {@link Privilege} has access to the given {@link Restrictable}
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
|
@ -38,29 +38,29 @@ import li.strolch.privilege.model.internal.User;
|
|||
public interface PrivilegePolicy {
|
||||
|
||||
/**
|
||||
* Checks if the given {@link Role} and the given {@link IPrivilege} has access to the given {@link Restrictable}
|
||||
* Checks if the given {@link Role} and the given {@link Privilege} has access to the given {@link Restrictable}
|
||||
*
|
||||
* @param context
|
||||
* the privilege context
|
||||
* @param privilege
|
||||
* the {@link IPrivilege} containing the permissions
|
||||
* the {@link Privilege} containing the permissions
|
||||
* @param restrictable
|
||||
* the {@link Restrictable} to which the user wants access
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if action not allowed
|
||||
*/
|
||||
void validateAction(PrivilegeContext context, IPrivilege privilege, Restrictable restrictable)
|
||||
void validateAction(PrivilegeContext context, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Returns true if the given {@link Role} and the given {@link IPrivilege} has access to the given {@link
|
||||
* Returns true if the given {@link Role} and the given {@link Privilege} has access to the given {@link
|
||||
* Restrictable}
|
||||
*
|
||||
* @param context
|
||||
* the privilege context
|
||||
* @param privilege
|
||||
* the {@link IPrivilege} containing the permissions
|
||||
* the {@link Privilege} containing the permissions
|
||||
* @param restrictable
|
||||
* the {@link Restrictable} to which the user wants access
|
||||
*
|
||||
|
@ -69,6 +69,6 @@ public interface PrivilegePolicy {
|
|||
* @throws AccessDeniedException
|
||||
* if something goes wrong with the validate
|
||||
*/
|
||||
boolean hasPrivilege(PrivilegeContext context, IPrivilege privilege, Restrictable restrictable)
|
||||
boolean hasPrivilege(PrivilegeContext context, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.text.MessageFormat;
|
|||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
@ -34,7 +34,7 @@ public class PrivilegePolicyHelper {
|
|||
* Validates the given values and returns the privilege name
|
||||
*
|
||||
* @param privilege
|
||||
* the {@link IPrivilege}
|
||||
* the {@link Privilege}
|
||||
* @param restrictable
|
||||
* the {@link Restrictable}
|
||||
*
|
||||
|
@ -43,7 +43,7 @@ public class PrivilegePolicyHelper {
|
|||
* @throws PrivilegeException
|
||||
* if something is wrong
|
||||
*/
|
||||
public static String preValidate(IPrivilege privilege, Restrictable restrictable) throws PrivilegeException {
|
||||
public static String preValidate(Privilege privilege, Restrictable restrictable) throws PrivilegeException {
|
||||
if (privilege == null)
|
||||
throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull"));
|
||||
if (restrictable == null)
|
||||
|
@ -88,7 +88,7 @@ public class PrivilegePolicyHelper {
|
|||
* @throws AccessDeniedException
|
||||
* if access is denied
|
||||
*/
|
||||
public static boolean checkByAllowDenyValues(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
public static boolean checkByAllowDenyValues(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
String privilegeValue, boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
// first check values not allowed
|
||||
|
@ -102,7 +102,7 @@ public class PrivilegePolicyHelper {
|
|||
return handleAccessDenied(ctx, privilege, restrictable, privilegeValue, assertHasPrivilege);
|
||||
}
|
||||
|
||||
private static boolean handleAccessDenied(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
private static boolean handleAccessDenied(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
String privilegeValue, boolean assertHasPrivilege) {
|
||||
|
||||
if (assertHasPrivilege) {
|
||||
|
|
|
@ -24,7 +24,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
|
@ -42,18 +42,18 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class RoleAccessPrivilege implements PrivilegePolicy {
|
||||
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
||||
private boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
private boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
String privilegeName = preValidate(privilege, restrictable);
|
||||
|
|
|
@ -24,7 +24,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
|
@ -41,18 +41,18 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UserAccessPrivilege implements PrivilegePolicy {
|
||||
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
String privilegeName = preValidate(privilege, restrictable);
|
||||
|
|
|
@ -28,7 +28,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
|
@ -43,13 +43,13 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege {
|
||||
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
String privilegeName = preValidate(privilege, restrictable);
|
||||
|
|
|
@ -24,7 +24,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
|
||||
|
@ -44,18 +44,18 @@ import li.strolch.privilege.model.Restrictable;
|
|||
public class UsernameFromCertificatePrivilege implements PrivilegePolicy {
|
||||
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
preValidate(privilege, restrictable);
|
||||
|
|
|
@ -28,7 +28,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Restrictable;
|
||||
|
||||
|
@ -48,19 +48,19 @@ import li.strolch.privilege.model.Restrictable;
|
|||
public class UsernameFromCertificateWithSameOrganisationPrivilege extends UsernameFromCertificatePrivilege {
|
||||
|
||||
@Override
|
||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws AccessDeniedException {
|
||||
validateAction(ctx, privilege, restrictable, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
||||
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||
throws PrivilegeException {
|
||||
return validateAction(ctx, privilege, restrictable, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
||||
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||
|
||||
preValidate(privilege, restrictable);
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class CertificateStubsDomWriter {
|
||||
|
||||
private final List<Certificate> certificates;
|
||||
private final OutputStream outputStream;
|
||||
|
||||
public CertificateStubsDomWriter(List<Certificate> certificates, OutputStream outputStream) {
|
||||
this.certificates = certificates;
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
public void write() {
|
||||
|
||||
// create document root
|
||||
Document doc = XmlHelper.createDocument();
|
||||
Element rootElement = doc.createElement(XML_ROOT_CERTIFICATES);
|
||||
doc.appendChild(rootElement);
|
||||
|
||||
this.certificates.stream().sorted(comparing(Certificate::getSessionId)).forEach(cert -> {
|
||||
|
||||
// create the certificate element
|
||||
Element certElement = doc.createElement(XML_CERTIFICATE);
|
||||
rootElement.appendChild(certElement);
|
||||
|
||||
// sessionId;
|
||||
certElement.setAttribute(XML_ATTR_SESSION_ID, cert.getSessionId());
|
||||
|
||||
// usage;
|
||||
certElement.setAttribute(XML_ATTR_USAGE, cert.getUsage().name());
|
||||
|
||||
// username;
|
||||
certElement.setAttribute(XML_ATTR_USERNAME, cert.getUsername());
|
||||
|
||||
// authToken;
|
||||
certElement.setAttribute(XML_ATTR_AUTH_TOKEN, cert.getAuthToken());
|
||||
|
||||
// source;
|
||||
certElement.setAttribute(XML_ATTR_SOURCE, cert.getSource());
|
||||
|
||||
// locale;
|
||||
certElement.setAttribute(XML_ATTR_LOCALE, cert.getLocale().toLanguageTag());
|
||||
|
||||
// loginTime;
|
||||
certElement.setAttribute(XML_ATTR_LOGIN_TIME, ISO8601.toString(cert.getLoginTime()));
|
||||
|
||||
// lastAccess;
|
||||
certElement.setAttribute(XML_ATTR_LAST_ACCESS, ISO8601.toString(cert.getLastAccess()));
|
||||
|
||||
// keepAlive;
|
||||
certElement.setAttribute(XML_ATTR_KEEP_ALIVE, String.valueOf(cert.isKeepAlive()));
|
||||
});
|
||||
|
||||
// write the container file to disk
|
||||
XmlHelper.writeDocument(doc, this.outputStream);
|
||||
}
|
||||
}
|
|
@ -15,16 +15,6 @@
|
|||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static li.strolch.privilege.handler.DefaultPrivilegeHandler.SOURCE_UNKNOWN;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
@ -33,6 +23,16 @@ import li.strolch.utils.iso8601.ISO8601;
|
|||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static li.strolch.privilege.handler.DefaultPrivilegeHandler.SOURCE_UNKNOWN;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -55,33 +55,27 @@ public class CertificateStubsSaxReader extends DefaultHandler {
|
|||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
|
||||
switch (qName) {
|
||||
case XML_ROOT_CERTIFICATES:
|
||||
break;
|
||||
case XML_CERTIFICATE:
|
||||
|
||||
CertificateStub stub = new CertificateStub();
|
||||
stub.usage = Usage.valueOf(attributes.getValue(XML_ATTR_USAGE).trim());
|
||||
stub.sessionId = attributes.getValue(XML_ATTR_SESSION_ID).trim();
|
||||
stub.username = attributes.getValue(XML_ATTR_USERNAME).trim();
|
||||
stub.authToken = attributes.getValue(XML_ATTR_AUTH_TOKEN).trim();
|
||||
stub.source = attributes.getValue(XML_ATTR_SOURCE).trim();
|
||||
stub.locale = Locale.forLanguageTag(attributes.getValue(XML_ATTR_LOCALE).trim());
|
||||
stub.loginTime = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LOGIN_TIME).trim());
|
||||
stub.lastAccess = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LAST_ACCESS).trim());
|
||||
stub.keepAlive = Boolean.parseBoolean(attributes.getValue(XML_ATTR_KEEP_ALIVE).trim());
|
||||
|
||||
DBC.INTERIM.assertNotEmpty("sessionId missing on sessions data!", stub.sessionId);
|
||||
DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username);
|
||||
DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken);
|
||||
|
||||
if (isEmpty(stub.source))
|
||||
stub.source = SOURCE_UNKNOWN;
|
||||
|
||||
this.stubs.add(stub);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new PrivilegeException("Unhandled tag " + qName);
|
||||
case ROOT_CERTIFICATES -> {
|
||||
}
|
||||
case CERTIFICATE -> {
|
||||
CertificateStub stub = new CertificateStub();
|
||||
stub.usage = Usage.valueOf(attributes.getValue(ATTR_USAGE).trim());
|
||||
stub.sessionId = attributes.getValue(ATTR_SESSION_ID).trim();
|
||||
stub.username = attributes.getValue(ATTR_USERNAME).trim();
|
||||
stub.authToken = attributes.getValue(ATTR_AUTH_TOKEN).trim();
|
||||
stub.source = attributes.getValue(ATTR_SOURCE).trim();
|
||||
stub.locale = Locale.forLanguageTag(attributes.getValue(ATTR_LOCALE).trim());
|
||||
stub.loginTime = ISO8601.parseToZdt(attributes.getValue(ATTR_LOGIN_TIME).trim());
|
||||
stub.lastAccess = ISO8601.parseToZdt(attributes.getValue(ATTR_LAST_ACCESS).trim());
|
||||
stub.keepAlive = Boolean.parseBoolean(attributes.getValue(ATTR_KEEP_ALIVE).trim());
|
||||
DBC.INTERIM.assertNotEmpty("sessionId missing on sessions data!", stub.sessionId);
|
||||
DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username);
|
||||
DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken);
|
||||
if (isEmpty(stub.source))
|
||||
stub.source = SOURCE_UNKNOWN;
|
||||
this.stubs.add(stub);
|
||||
}
|
||||
default -> throw new PrivilegeException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.helper.XmlHelper.openXmlStreamWriterDocument;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class CertificateStubsSaxWriter {
|
||||
|
||||
private final List<Certificate> certificates;
|
||||
private final OutputStream outputStream;
|
||||
|
||||
public CertificateStubsSaxWriter(List<Certificate> certificates, OutputStream outputStream) {
|
||||
this.certificates = certificates;
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
public void write() throws IOException, XMLStreamException {
|
||||
|
||||
Writer ioWriter = new OutputStreamWriter(this.outputStream, StandardCharsets.UTF_8);
|
||||
|
||||
IndentingXMLStreamWriter xmlWriter = openXmlStreamWriterDocument(ioWriter);
|
||||
xmlWriter.writeStartElement(ROOT_CERTIFICATES);
|
||||
|
||||
List<Certificate> certificates = new ArrayList<>(this.certificates);
|
||||
certificates.sort(comparing(Certificate::getSessionId));
|
||||
for (Certificate cert : certificates) {
|
||||
|
||||
// create the certificate element
|
||||
xmlWriter.writeStartElement(CERTIFICATE);
|
||||
|
||||
// sessionId;
|
||||
xmlWriter.writeAttribute(ATTR_SESSION_ID, cert.getSessionId());
|
||||
|
||||
// usage;
|
||||
xmlWriter.writeAttribute(ATTR_USAGE, cert.getUsage().name());
|
||||
|
||||
// username;
|
||||
xmlWriter.writeAttribute(ATTR_USERNAME, cert.getUsername());
|
||||
|
||||
// authToken;
|
||||
xmlWriter.writeAttribute(ATTR_AUTH_TOKEN, cert.getAuthToken());
|
||||
|
||||
// source;
|
||||
xmlWriter.writeAttribute(ATTR_SOURCE, cert.getSource());
|
||||
|
||||
// locale;
|
||||
xmlWriter.writeAttribute(ATTR_LOCALE, cert.getLocale().toLanguageTag());
|
||||
|
||||
// loginTime;
|
||||
xmlWriter.writeAttribute(ATTR_LOGIN_TIME, ISO8601.toString(cert.getLoginTime()));
|
||||
|
||||
// lastAccess;
|
||||
xmlWriter.writeAttribute(ATTR_LAST_ACCESS, ISO8601.toString(cert.getLastAccess()));
|
||||
|
||||
// keepAlive;
|
||||
xmlWriter.writeAttribute(ATTR_KEEP_ALIVE, String.valueOf(cert.isKeepAlive()));
|
||||
}
|
||||
|
||||
// and now end
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ package li.strolch.privilege.xml;
|
|||
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
// TODO write JavaDoc...
|
||||
public interface ElementParser {
|
||||
|
||||
void startElement(String uri, String localName, String qName, Attributes attributes);
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import li.strolch.privilege.model.internal.PrivilegeContainerModel;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeConfigDomWriter {
|
||||
|
||||
private final PrivilegeContainerModel containerModel;
|
||||
private final File configFile;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PrivilegeConfigDomWriter(PrivilegeContainerModel containerModel, File configFile) {
|
||||
this.containerModel = containerModel;
|
||||
this.configFile = configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void write() {
|
||||
|
||||
// create document root
|
||||
Document doc = XmlHelper.createDocument();
|
||||
Element rootElement = doc.createElement(XML_ROOT_PRIVILEGE);
|
||||
doc.appendChild(rootElement);
|
||||
|
||||
Element containerElement = doc.createElement(XML_CONTAINER);
|
||||
rootElement.appendChild(containerElement);
|
||||
|
||||
// create EncryptionHandler
|
||||
Element encryptionHandlerElem = doc.createElement(XML_HANDLER_ENCRYPTION);
|
||||
containerElement.appendChild(encryptionHandlerElem);
|
||||
encryptionHandlerElem.setAttribute(XML_ATTR_CLASS, this.containerModel.getEncryptionHandlerClassName());
|
||||
// Parameters
|
||||
fillParameterMap(doc, encryptionHandlerElem, this.containerModel.getEncryptionHandlerParameterMap());
|
||||
|
||||
// create PersistenceHandler
|
||||
Element persistenceHandlerElem = doc.createElement(XML_HANDLER_PERSISTENCE);
|
||||
containerElement.appendChild(persistenceHandlerElem);
|
||||
persistenceHandlerElem.setAttribute(XML_ATTR_CLASS, this.containerModel.getPersistenceHandlerClassName());
|
||||
// Parameters
|
||||
fillParameterMap(doc, persistenceHandlerElem, this.containerModel.getPersistenceHandlerParameterMap());
|
||||
|
||||
// Parameters
|
||||
fillParameterMap(doc, containerElement, this.containerModel.getParameterMap());
|
||||
|
||||
// create UserChallengeHandler
|
||||
Element userChallengeHandlerElem = doc.createElement(XML_HANDLER_USER_CHALLENGE);
|
||||
containerElement.appendChild(userChallengeHandlerElem);
|
||||
userChallengeHandlerElem.setAttribute(XML_ATTR_CLASS, this.containerModel.getUserChallengeHandlerClassName());
|
||||
// Parameters
|
||||
fillParameterMap(doc, userChallengeHandlerElem, this.containerModel.getUserChallengeHandlerParameterMap());
|
||||
|
||||
// create SingleSignOnHandler
|
||||
if (this.containerModel.getSsoHandlerClassName() != null) {
|
||||
Element ssoHandlerElem = doc.createElement(XML_HANDLER_SSO);
|
||||
containerElement.appendChild(ssoHandlerElem);
|
||||
ssoHandlerElem.setAttribute(XML_ATTR_CLASS, this.containerModel.getSsoHandlerClassName());
|
||||
// Parameters
|
||||
fillParameterMap(doc, ssoHandlerElem, this.containerModel.getSsoHandlerParameterMap());
|
||||
}
|
||||
|
||||
// create PrivilegeHandler
|
||||
if (this.containerModel.getSsoHandlerClassName() != null) {
|
||||
Element privilegeHandlerElem = doc.createElement(XML_HANDLER_PRIVILEGE);
|
||||
containerElement.appendChild(privilegeHandlerElem);
|
||||
privilegeHandlerElem.setAttribute(XML_ATTR_CLASS, this.containerModel.getPrivilegeHandlerClassName());
|
||||
// Parameters
|
||||
fillParameterMap(doc, privilegeHandlerElem, this.containerModel.getPrivilegeHandlerParameterMap());
|
||||
}
|
||||
|
||||
// Policies
|
||||
Element policiesElem = doc.createElement(XML_POLICIES);
|
||||
rootElement.appendChild(policiesElem);
|
||||
this.containerModel.getPolicies().entrySet().stream().sorted(Entry.comparingByKey())
|
||||
.forEach(entry -> {
|
||||
Element policyElem = doc.createElement(XML_POLICY);
|
||||
policyElem.setAttribute(XML_ATTR_NAME, entry.getKey());
|
||||
policyElem.setAttribute(XML_ATTR_CLASS, entry.getValue().getName());
|
||||
policiesElem.appendChild(policyElem);
|
||||
});
|
||||
|
||||
// write the container file to disk
|
||||
XmlHelper.writeDocument(doc, this.configFile);
|
||||
}
|
||||
|
||||
private void fillParameterMap(Document doc, Element parent, Map<String, String> parameterMap) {
|
||||
|
||||
if (parameterMap != null && !parameterMap.isEmpty()) {
|
||||
Element parametersElement = doc.createElement(XML_PARAMETERS);
|
||||
for (Entry<String, String> entry : parameterMap.entrySet()) {
|
||||
Element parameterElement = doc.createElement(XML_PARAMETER);
|
||||
parameterElement.setAttribute(XML_ATTR_NAME, entry.getKey());
|
||||
parameterElement.setAttribute(XML_ATTR_VALUE, entry.getValue());
|
||||
parametersElement.appendChild(parameterElement);
|
||||
}
|
||||
|
||||
parent.appendChild(parametersElement);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,18 +15,17 @@
|
|||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import li.strolch.privilege.model.internal.PrivilegeContainerModel;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.internal.PrivilegeContainerModel;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -48,12 +47,12 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
|
||||
switch (qName) {
|
||||
case XML_CONTAINER -> this.buildersStack.push(new ContainerParser());
|
||||
case XML_PARAMETERS -> this.buildersStack.push(new ParametersParser());
|
||||
case XML_POLICIES -> this.buildersStack.push(new PoliciesParser());
|
||||
default -> {
|
||||
// nothing to do, probably handle on stack
|
||||
}
|
||||
case CONTAINER -> this.buildersStack.push(new ContainerParser());
|
||||
case PARAMETERS -> this.buildersStack.push(new ParametersParser());
|
||||
case POLICIES -> this.buildersStack.push(new PoliciesParser());
|
||||
default -> {
|
||||
// nothing to do, probably handle on stack
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.buildersStack.isEmpty())
|
||||
|
@ -73,7 +72,7 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||
|
||||
ElementParser elementParser = switch (qName) {
|
||||
case XML_CONTAINER, XML_PARAMETERS, XML_POLICIES -> this.buildersStack.pop();
|
||||
case CONTAINER, PARAMETERS, POLICIES -> this.buildersStack.pop();
|
||||
default -> null;
|
||||
};
|
||||
|
||||
|
@ -89,38 +88,38 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
|
||||
switch (qName) {
|
||||
case XML_CONTAINER -> this.currentElement = qName;
|
||||
case XML_HANDLER_ENCRYPTION -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setEncryptionHandlerClassName(className);
|
||||
}
|
||||
case XML_HANDLER_PASSWORD_STRENGTH -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setPasswordStrengthHandlerClassName(className);
|
||||
}
|
||||
case XML_HANDLER_PERSISTENCE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setPersistenceHandlerClassName(className);
|
||||
}
|
||||
case XML_HANDLER_USER_CHALLENGE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setUserChallengeHandlerClassName(className);
|
||||
}
|
||||
case XML_HANDLER_SSO -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setSsoHandlerClassName(className);
|
||||
}
|
||||
case XML_HANDLER_PRIVILEGE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
getContainerModel().setPrivilegeHandlerClassName(className);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||
case CONTAINER -> this.currentElement = qName;
|
||||
case HANDLER_PRIVILEGE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setPrivilegeHandlerClassName(className);
|
||||
}
|
||||
case HANDLER_ENCRYPTION -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setEncryptionHandlerClassName(className);
|
||||
}
|
||||
case HANDLER_PASSWORD_STRENGTH -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setPasswordStrengthHandlerClassName(className);
|
||||
}
|
||||
case HANDLER_PERSISTENCE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setPersistenceHandlerClassName(className);
|
||||
}
|
||||
case HANDLER_USER_CHALLENGE -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setUserChallengeHandlerClassName(className);
|
||||
}
|
||||
case HANDLER_SSO -> {
|
||||
this.currentElement = qName;
|
||||
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||
getContainerModel().setSsoHandlerClassName(className);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,20 +128,17 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
if (!(child instanceof ParametersParser parametersChild))
|
||||
return;
|
||||
|
||||
final Map<String, String> params = parametersChild.getParameterMap();
|
||||
switch (this.currentElement) {
|
||||
case XML_CONTAINER -> getContainerModel().setParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_ENCRYPTION ->
|
||||
getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_PASSWORD_STRENGTH ->
|
||||
getContainerModel().setPasswordStrengthHandlerParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_PERSISTENCE ->
|
||||
getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_USER_CHALLENGE ->
|
||||
getContainerModel().setUserChallengeHandlerParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_SSO -> getContainerModel().setSsoHandlerParameterMap(parametersChild.getParameterMap());
|
||||
case XML_HANDLER_PRIVILEGE ->
|
||||
getContainerModel().setPrivilegeHandlerParameterMap(parametersChild.getParameterMap());
|
||||
default -> throw new IllegalStateException("Unexpected value: " + this.currentElement);
|
||||
case CONTAINER -> getContainerModel().setParameterMap(params);
|
||||
case HANDLER_PRIVILEGE -> getContainerModel().setPrivilegeHandlerParameterMap(params);
|
||||
case HANDLER_ENCRYPTION -> getContainerModel().setEncryptionHandlerParameterMap(params);
|
||||
case HANDLER_PASSWORD_STRENGTH ->
|
||||
getContainerModel().setPasswordStrengthHandlerParameterMap(params);
|
||||
case HANDLER_PERSISTENCE -> getContainerModel().setPersistenceHandlerParameterMap(params);
|
||||
case HANDLER_USER_CHALLENGE -> getContainerModel().setUserChallengeHandlerParameterMap(params);
|
||||
case HANDLER_SSO -> getContainerModel().setSsoHandlerParameterMap(params);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + this.currentElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,9 +151,9 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
if (qName.equals(XML_PARAMETER)) {
|
||||
String key = attributes.getValue(XML_ATTR_NAME).trim();
|
||||
String value = attributes.getValue(XML_ATTR_VALUE).trim();
|
||||
if (qName.equals(PARAMETER)) {
|
||||
String key = attributes.getValue(ATTR_NAME).trim();
|
||||
String value = attributes.getValue(ATTR_VALUE).trim();
|
||||
this.parameterMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
@ -176,9 +172,9 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
|||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
if (qName.equals(XML_POLICY)) {
|
||||
String policyName = attributes.getValue(XML_ATTR_NAME).trim();
|
||||
String policyClassName = attributes.getValue(XML_ATTR_CLASS).trim();
|
||||
if (qName.equals(POLICY)) {
|
||||
String policyName = attributes.getValue(ATTR_NAME).trim();
|
||||
String policyClassName = attributes.getValue(ATTR_CLASS).trim();
|
||||
|
||||
getContainerModel().addPolicy(policyName, policyClassName);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
import li.strolch.privilege.model.internal.PrivilegeContainerModel;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.helper.XmlHelper.openXmlStreamWriterDocument;
|
||||
import static li.strolch.privilege.helper.XmlHelper.writeStringMapElement;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeConfigSaxWriter {
|
||||
|
||||
private final PrivilegeContainerModel containerModel;
|
||||
private final File configFile;
|
||||
|
||||
public PrivilegeConfigSaxWriter(PrivilegeContainerModel containerModel, File configFile) {
|
||||
this.containerModel = containerModel;
|
||||
this.configFile = configFile;
|
||||
}
|
||||
|
||||
public void write() throws IOException, XMLStreamException {
|
||||
|
||||
try (Writer ioWriter = new OutputStreamWriter(new FileOutputStream(this.configFile), StandardCharsets.UTF_8)) {
|
||||
|
||||
IndentingXMLStreamWriter xmlWriter = openXmlStreamWriterDocument(ioWriter);
|
||||
xmlWriter.writeStartElement(ROOT_PRIVILEGE);
|
||||
|
||||
// write container element
|
||||
xmlWriter.writeStartElement(CONTAINER);
|
||||
writeStringMapElement(xmlWriter, this.containerModel.getParameterMap(), PARAMETERS, PARAMETER);
|
||||
|
||||
{
|
||||
// write PrivilegeHandler
|
||||
if (this.containerModel.getPrivilegeHandlerClassName() != null)
|
||||
writeHandler(xmlWriter, HANDLER_PRIVILEGE, this.containerModel.getPrivilegeHandlerClassName(),
|
||||
this.containerModel.getPrivilegeHandlerParameterMap());
|
||||
|
||||
// write EncryptionHandler
|
||||
writeHandler(xmlWriter, HANDLER_ENCRYPTION, this.containerModel.getEncryptionHandlerClassName(),
|
||||
this.containerModel.getEncryptionHandlerParameterMap());
|
||||
|
||||
// write PersistenceHandler
|
||||
writeHandler(xmlWriter, HANDLER_PERSISTENCE, this.containerModel.getPersistenceHandlerClassName(),
|
||||
this.containerModel.getPersistenceHandlerParameterMap());
|
||||
|
||||
// write PasswordStrengthHandler
|
||||
if (this.containerModel.getPasswordStrengthHandlerClassName() != null)
|
||||
writeHandler(xmlWriter, HANDLER_PASSWORD_STRENGTH,
|
||||
this.containerModel.getPasswordStrengthHandlerClassName(),
|
||||
this.containerModel.getPasswordStrengthHandlerParameterMap());
|
||||
|
||||
// write UserChallengeHandler
|
||||
if (this.containerModel.getUserChallengeHandlerClassName() != null)
|
||||
writeHandler(xmlWriter, HANDLER_USER_CHALLENGE,
|
||||
this.containerModel.getUserChallengeHandlerClassName(),
|
||||
this.containerModel.getUserChallengeHandlerParameterMap());
|
||||
|
||||
// write SingleSignOnHandler
|
||||
if (this.containerModel.getSsoHandlerClassName() != null)
|
||||
writeHandler(xmlWriter, HANDLER_SSO, this.containerModel.getSsoHandlerClassName(),
|
||||
this.containerModel.getSsoHandlerParameterMap());
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
|
||||
// Policies
|
||||
Map<String, String> policies = new HashMap<>();
|
||||
this.containerModel.getPolicies().forEach((key, value) -> policies.put(key, value.getName()));
|
||||
writeStringMapElement(xmlWriter, policies, POLICIES, POLICY, ATTR_CLASS);
|
||||
|
||||
// and now end
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHandler(IndentingXMLStreamWriter xmlWriter, String handleName, String className,
|
||||
Map<String, String> parameters) throws XMLStreamException {
|
||||
if (parameters.isEmpty())
|
||||
xmlWriter.writeEmptyElement(handleName);
|
||||
else
|
||||
xmlWriter.writeStartElement(handleName);
|
||||
xmlWriter.writeAttribute(ATTR_CLASS, className);
|
||||
|
||||
writeStringMapElement(xmlWriter, parameters, PARAMETERS, PARAMETER);
|
||||
|
||||
if (!parameters.isEmpty())
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeGroupsSaxReader extends DefaultHandler {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(PrivilegeGroupsSaxReader.class);
|
||||
|
||||
private final Deque<ElementParser> buildersStack = new ArrayDeque<>();
|
||||
|
||||
private final Map<String, Group> groups;
|
||||
|
||||
public PrivilegeGroupsSaxReader() {
|
||||
this.groups = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the users
|
||||
*/
|
||||
public Map<String, Group> getGroups() {
|
||||
return this.groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equals(GROUP)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(GroupParser.class)))
|
||||
throw new IllegalArgumentException("Previous Group not closed!");
|
||||
this.buildersStack.push(new GroupParser());
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(PropertyParser.class)))
|
||||
throw new IllegalArgumentException("Previous Properties not closed!");
|
||||
this.buildersStack.push(new PropertyParser());
|
||||
}
|
||||
|
||||
if (!this.buildersStack.isEmpty())
|
||||
this.buildersStack.peek().startElement(uri, localName, qName, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
if (!this.buildersStack.isEmpty())
|
||||
this.buildersStack.peek().characters(ch, start, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
|
||||
if (!this.buildersStack.isEmpty())
|
||||
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||
|
||||
ElementParser elementParser = null;
|
||||
if (qName.equals(GROUP)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
}
|
||||
|
||||
if (!this.buildersStack.isEmpty() && elementParser != null)
|
||||
this.buildersStack.peek().notifyChild(elementParser);
|
||||
}
|
||||
|
||||
// <User userId="1" username="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
|
||||
// <Firstname>Application</Firstname>
|
||||
// <Lastname>Administrator</Lastname>
|
||||
// <State>ENABLED</State>
|
||||
// <Locale>en-GB</Locale>
|
||||
// <Roles>
|
||||
// <Role>PrivilegeAdmin</Role>
|
||||
// <Role>AppUser</Role>
|
||||
// </Roles>
|
||||
// <Properties>
|
||||
// <Property name="organization" value="eitchnet.ch" />
|
||||
// <Property name="organizationalUnit" value="Development" />
|
||||
// </Properties>
|
||||
// <History>
|
||||
// <FirstLogin>2021-02-19T15:32:09.592+01:00</FirstLogin>
|
||||
// <LastLogin>2021-02-19T15:32:09.592+01:00</LastLogin>
|
||||
// <LastPasswordChange>2021-02-19T15:32:09.592+01:00</LastPasswordChange>
|
||||
// </History>
|
||||
// </User>
|
||||
|
||||
public class GroupParser extends ElementParserAdapter {
|
||||
|
||||
StringBuilder text;
|
||||
|
||||
String name;
|
||||
final Set<String> roles;
|
||||
Map<String, String> parameters;
|
||||
|
||||
public GroupParser() {
|
||||
this.roles = new HashSet<>();
|
||||
this.parameters = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
|
||||
this.text = new StringBuilder();
|
||||
|
||||
if (qName.equals(GROUP)) {
|
||||
this.name = attributes.getValue(ATTR_NAME).trim();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) {
|
||||
this.text.append(ch, start, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
|
||||
switch (qName) {
|
||||
case ROLE -> this.roles.add(getText());
|
||||
case GROUP -> {
|
||||
|
||||
Group group = new Group(this.name, this.roles, this.parameters);
|
||||
|
||||
logger.info(MessageFormat.format("New Group: {0}", group));
|
||||
groups.put(this.name, group);
|
||||
}
|
||||
default -> {
|
||||
if (!(qName.equals(GROUPS) //
|
||||
|| qName.equals(ROLES) //
|
||||
|| qName.equals(PARAMETER) //
|
||||
|| qName.equals(PARAMETERS))) {
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getText() {
|
||||
return this.text.toString().trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyChild(ElementParser child) {
|
||||
if (child instanceof PropertyParser) {
|
||||
this.parameters = ((PropertyParser) child).parameterMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.helper.XmlHelper.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeGroupsSaxWriter {
|
||||
|
||||
private final List<Group> groups;
|
||||
private final File modelFile;
|
||||
|
||||
public PrivilegeGroupsSaxWriter(List<Group> groups, File modelFile) {
|
||||
this.groups = groups;
|
||||
this.modelFile = modelFile;
|
||||
}
|
||||
|
||||
public void write() throws IOException, XMLStreamException {
|
||||
|
||||
try (Writer ioWriter = new OutputStreamWriter(new FileOutputStream(this.modelFile), StandardCharsets.UTF_8)) {
|
||||
|
||||
IndentingXMLStreamWriter xmlWriter = openXmlStreamWriterDocument(ioWriter);
|
||||
xmlWriter.writeStartElement(GROUPS);
|
||||
|
||||
List<Group> groups = new ArrayList<>(this.groups);
|
||||
groups.sort(comparing(g -> g.name().toLowerCase(Locale.ROOT)));
|
||||
for (Group group : this.groups) {
|
||||
|
||||
// start the user element
|
||||
xmlWriter.writeStartElement(GROUP);
|
||||
|
||||
xmlWriter.writeAttribute(ATTR_NAME, group.name());
|
||||
|
||||
// add all the role elements
|
||||
if (!group.roles().isEmpty()) {
|
||||
xmlWriter.writeStartElement(ROLES);
|
||||
writeStringList(xmlWriter, ROLE, group.roles());
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// add the parameters
|
||||
Map<String, String> properties = group.getProperties();
|
||||
if (!properties.isEmpty())
|
||||
writeStringMapElement(xmlWriter, properties, PROPERTIES, PROPERTY);
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// and now end
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeRolesDomWriter {
|
||||
|
||||
private final List<Role> roles;
|
||||
private final File modelFile;
|
||||
|
||||
public PrivilegeRolesDomWriter(List<Role> roles, File modelFile) {
|
||||
this.roles = roles;
|
||||
this.modelFile = modelFile;
|
||||
}
|
||||
|
||||
public void write() {
|
||||
|
||||
// create document root
|
||||
Document doc = XmlHelper.createDocument();
|
||||
Element rootElement = doc.createElement(XmlConstants.XML_ROLES);
|
||||
doc.appendChild(rootElement);
|
||||
|
||||
this.roles.stream().sorted(comparing(role1 -> role1.getName().toLowerCase(Locale.ROOT))).forEach(role -> {
|
||||
|
||||
// create the role element
|
||||
Element roleElement = doc.createElement(XmlConstants.XML_ROLE);
|
||||
rootElement.appendChild(roleElement);
|
||||
|
||||
roleElement.setAttribute(XmlConstants.XML_ATTR_NAME, role.getName());
|
||||
|
||||
role.getPrivilegeNames().stream().sorted().map(role::getPrivilege).forEach(privilege -> {
|
||||
Element privilegeElement = doc.createElement(XmlConstants.XML_PRIVILEGE);
|
||||
roleElement.appendChild(privilegeElement);
|
||||
privilegeElement.setAttribute(XmlConstants.XML_ATTR_NAME, privilege.getName());
|
||||
privilegeElement.setAttribute(XmlConstants.XML_ATTR_POLICY, privilege.getPolicy());
|
||||
|
||||
if (privilege.isAllAllowed()) {
|
||||
Element allAllowedElement = doc.createElement(XmlConstants.XML_ALL_ALLOWED);
|
||||
allAllowedElement.setTextContent(Boolean.toString(privilege.isAllAllowed()));
|
||||
privilegeElement.appendChild(allAllowedElement);
|
||||
}
|
||||
|
||||
privilege.getDenyList().stream().sorted().forEach(denyValue -> {
|
||||
Element denyValueElement = doc.createElement(XmlConstants.XML_DENY);
|
||||
denyValueElement.setTextContent(denyValue);
|
||||
privilegeElement.appendChild(denyValueElement);
|
||||
});
|
||||
|
||||
privilege.getAllowList().stream().sorted().forEach(allowValue -> {
|
||||
Element allowValueElement = doc.createElement(XmlConstants.XML_ALLOW);
|
||||
allowValueElement.setTextContent(allowValue);
|
||||
privilegeElement.appendChild(allowValueElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// write the container file to disk
|
||||
XmlHelper.writeDocument(doc, this.modelFile);
|
||||
}
|
||||
}
|
|
@ -15,12 +15,7 @@
|
|||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.internal.PrivilegeImpl;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -29,6 +24,11 @@ import org.xml.sax.Attributes;
|
|||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -51,9 +51,13 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
|
||||
if (qName.equals(XmlConstants.XML_ROLE)) {
|
||||
if (qName.equals(ROLE)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(RoleParser.class)))
|
||||
throw new IllegalArgumentException("Previous Role not closed!");
|
||||
this.buildersStack.push(new RoleParser());
|
||||
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(PropertyParser.class)))
|
||||
throw new IllegalArgumentException("Previous Properties not closed!");
|
||||
this.buildersStack.push(new PropertyParser());
|
||||
}
|
||||
|
||||
|
@ -74,9 +78,9 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||
|
||||
ElementParser elementParser = null;
|
||||
if (qName.equals(XmlConstants.XML_ROLE)) {
|
||||
if (qName.equals(ROLE)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
}
|
||||
|
||||
|
@ -109,7 +113,7 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
private Set<String> denyList;
|
||||
private Set<String> allowList;
|
||||
|
||||
private Map<String, IPrivilege> privileges;
|
||||
private Map<String, Privilege> privileges;
|
||||
|
||||
public RoleParser() {
|
||||
init();
|
||||
|
@ -134,20 +138,15 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
this.text = new StringBuilder();
|
||||
|
||||
switch (qName) {
|
||||
case XmlConstants.XML_ROLE:
|
||||
this.roleName = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
||||
break;
|
||||
case XmlConstants.XML_PRIVILEGE:
|
||||
this.privilegeName = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
||||
this.privilegePolicy = attributes.getValue(XmlConstants.XML_ATTR_POLICY).trim();
|
||||
break;
|
||||
case XmlConstants.XML_ALLOW:
|
||||
case XmlConstants.XML_DENY:
|
||||
case XmlConstants.XML_ALL_ALLOWED:
|
||||
case ROLE -> this.roleName = attributes.getValue(ATTR_NAME).trim();
|
||||
case PRIVILEGE -> {
|
||||
this.privilegeName = attributes.getValue(ATTR_NAME).trim();
|
||||
this.privilegePolicy = attributes.getValue(ATTR_POLICY).trim();
|
||||
}
|
||||
case ALLOW, DENY, ALL_ALLOWED -> {
|
||||
}
|
||||
// no-op
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
default -> throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,31 +158,33 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
|
||||
switch (qName) {
|
||||
case XmlConstants.XML_ALL_ALLOWED ->
|
||||
this.allAllowed = StringHelper.parseBoolean(this.text.toString().trim());
|
||||
case XmlConstants.XML_ALLOW -> this.allowList.add(this.text.toString().trim());
|
||||
case XmlConstants.XML_DENY -> this.denyList.add(this.text.toString().trim());
|
||||
case XmlConstants.XML_PRIVILEGE -> {
|
||||
IPrivilege privilege = new PrivilegeImpl(this.privilegeName, this.privilegePolicy, this.allAllowed,
|
||||
this.denyList, this.allowList);
|
||||
this.privileges.put(this.privilegeName, privilege);
|
||||
this.privilegeName = null;
|
||||
this.privilegePolicy = null;
|
||||
this.allAllowed = false;
|
||||
this.denyList = new HashSet<>();
|
||||
this.allowList = new HashSet<>();
|
||||
}
|
||||
case XmlConstants.XML_ROLE -> {
|
||||
Role role = new Role(this.roleName, this.privileges);
|
||||
roles.put(role.getName(), role);
|
||||
logger.info(MessageFormat.format("New Role: {0}", role));
|
||||
init();
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||
case ALL_ALLOWED -> this.allAllowed = StringHelper.parseBoolean(getText());
|
||||
case ALLOW -> this.allowList.add(getText());
|
||||
case DENY -> this.denyList.add(getText());
|
||||
case PRIVILEGE -> {
|
||||
Privilege privilege = new Privilege(this.privilegeName, this.privilegePolicy, this.allAllowed,
|
||||
this.denyList, this.allowList);
|
||||
this.privileges.put(this.privilegeName, privilege);
|
||||
this.privilegeName = null;
|
||||
this.privilegePolicy = null;
|
||||
this.allAllowed = false;
|
||||
this.denyList = new HashSet<>();
|
||||
this.allowList = new HashSet<>();
|
||||
}
|
||||
case ROLE -> {
|
||||
Role role = new Role(this.roleName, this.privileges);
|
||||
roles.put(role.getName(), role);
|
||||
logger.info(MessageFormat.format("New Role: {0}", role));
|
||||
init();
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||
}
|
||||
}
|
||||
|
||||
private String getText() {
|
||||
return this.text.toString().trim();
|
||||
}
|
||||
}
|
||||
|
||||
static class PropertyParser extends ElementParserAdapter {
|
||||
|
@ -194,11 +195,11 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
|||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
if (qName.equals(XmlConstants.XML_PROPERTY)) {
|
||||
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
||||
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE).trim();
|
||||
if (qName.equals(PROPERTY)) {
|
||||
String key = attributes.getValue(ATTR_NAME).trim();
|
||||
String value = attributes.getValue(ATTR_VALUE).trim();
|
||||
this.parameterMap.put(key, value);
|
||||
} else if (!qName.equals(XmlConstants.XML_PROPERTIES)) {
|
||||
} else if (!qName.equals(PROPERTIES)) {
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.internal.Role;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.helper.XmlHelper.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeRolesSaxWriter {
|
||||
|
||||
private final List<Role> roles;
|
||||
private final File modelFile;
|
||||
|
||||
public PrivilegeRolesSaxWriter(List<Role> roles, File modelFile) {
|
||||
this.roles = roles;
|
||||
this.modelFile = modelFile;
|
||||
}
|
||||
|
||||
public void write() throws IOException, XMLStreamException {
|
||||
|
||||
try (Writer ioWriter = new OutputStreamWriter(new FileOutputStream(this.modelFile), StandardCharsets.UTF_8)) {
|
||||
|
||||
IndentingXMLStreamWriter xmlWriter = openXmlStreamWriterDocument(ioWriter);
|
||||
xmlWriter.writeStartElement(ROLES);
|
||||
|
||||
List<Role> roles = new ArrayList<>(this.roles);
|
||||
roles.sort(comparing(r -> r.getName().toLowerCase(Locale.ROOT)));
|
||||
for (Role role : roles) {
|
||||
|
||||
// start the role element
|
||||
xmlWriter.writeStartElement(ROLE);
|
||||
xmlWriter.writeAttribute(ATTR_NAME, role.getName());
|
||||
|
||||
List<String> privilegeNames = new ArrayList<>(role.getPrivilegeNames());
|
||||
privilegeNames.sort(null);
|
||||
for (String privilegeName : privilegeNames) {
|
||||
Privilege privilege = role.getPrivilege(privilegeName);
|
||||
|
||||
xmlWriter.writeStartElement(PRIVILEGE);
|
||||
xmlWriter.writeAttribute(ATTR_NAME, privilege.getName());
|
||||
xmlWriter.writeAttribute(ATTR_POLICY, privilege.getPolicy());
|
||||
|
||||
if (privilege.isAllAllowed())
|
||||
writeStringElement(xmlWriter, ALL_ALLOWED, "true");
|
||||
writeStringList(xmlWriter, DENY, privilege.getDenyList());
|
||||
writeStringList(xmlWriter, ALLOW, privilege.getAllowList());
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// and now end
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.internal.PasswordCrypt;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.model.internal.PasswordCrypt.buildPasswordString;
|
||||
import static li.strolch.utils.helper.StringHelper.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeUsersDomWriter {
|
||||
|
||||
private final List<User> users;
|
||||
private final File modelFile;
|
||||
|
||||
public PrivilegeUsersDomWriter(List<User> users, File modelFile) {
|
||||
this.users = users;
|
||||
this.modelFile = modelFile;
|
||||
|
||||
this.users.sort(comparing(User::getUsername));
|
||||
}
|
||||
|
||||
public void write() {
|
||||
|
||||
// create document root
|
||||
Document doc = XmlHelper.createDocument();
|
||||
Element rootElement = doc.createElement(XML_USERS);
|
||||
doc.appendChild(rootElement);
|
||||
|
||||
this.users.forEach(user -> {
|
||||
|
||||
// create the user element
|
||||
Element userElement = doc.createElement(XML_USER);
|
||||
rootElement.appendChild(userElement);
|
||||
|
||||
userElement.setAttribute(XML_ATTR_USER_ID, user.getUserId());
|
||||
userElement.setAttribute(XML_ATTR_USERNAME, user.getUsername());
|
||||
writePassword(user, userElement);
|
||||
|
||||
// add first name element
|
||||
if (isNotEmpty(user.getFirstname())) {
|
||||
Element firstnameElement = doc.createElement(XML_FIRSTNAME);
|
||||
firstnameElement.setTextContent(user.getFirstname());
|
||||
userElement.appendChild(firstnameElement);
|
||||
}
|
||||
|
||||
// add last name element
|
||||
if (isNotEmpty(user.getLastname())) {
|
||||
Element lastnameElement = doc.createElement(XML_LASTNAME);
|
||||
lastnameElement.setTextContent(user.getLastname());
|
||||
userElement.appendChild(lastnameElement);
|
||||
}
|
||||
|
||||
// add state element
|
||||
Element stateElement = doc.createElement(XML_STATE);
|
||||
stateElement.setTextContent(user.getUserState().toString());
|
||||
userElement.appendChild(stateElement);
|
||||
|
||||
// add locale element
|
||||
Element localeElement = doc.createElement(XML_LOCALE);
|
||||
localeElement.setTextContent(user.getLocale().toLanguageTag());
|
||||
userElement.appendChild(localeElement);
|
||||
|
||||
// add password change requested element
|
||||
if (user.isPasswordChangeRequested()) {
|
||||
Element passwordChangeRequestedElement = doc.createElement(XML_PASSWORD_CHANGE_REQUESTED);
|
||||
passwordChangeRequestedElement.setTextContent(Boolean.toString(true));
|
||||
userElement.appendChild(passwordChangeRequestedElement);
|
||||
}
|
||||
|
||||
// add all the role elements
|
||||
Element rolesElement = doc.createElement(XML_ROLES);
|
||||
userElement.appendChild(rolesElement);
|
||||
user.getRoles().stream().sorted().forEach(roleName -> {
|
||||
Element roleElement = doc.createElement(XML_ROLE);
|
||||
roleElement.setTextContent(roleName);
|
||||
rolesElement.appendChild(roleElement);
|
||||
});
|
||||
|
||||
// add the parameters
|
||||
if (!user.getProperties().isEmpty()) {
|
||||
Element parametersElement = doc.createElement(XML_PROPERTIES);
|
||||
userElement.appendChild(parametersElement);
|
||||
user.getProperties().entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
||||
Element paramElement = doc.createElement(XML_PROPERTY);
|
||||
paramElement.setAttribute(XML_ATTR_NAME, entry.getKey());
|
||||
paramElement.setAttribute(XML_ATTR_VALUE, entry.getValue());
|
||||
parametersElement.appendChild(paramElement);
|
||||
});
|
||||
}
|
||||
|
||||
if (!user.isHistoryEmpty()) {
|
||||
UserHistory history = user.getHistory();
|
||||
Element historyElement = doc.createElement(XML_HISTORY);
|
||||
userElement.appendChild(historyElement);
|
||||
|
||||
if (!history.isFirstLoginEmpty()) {
|
||||
Element element = doc.createElement(XML_FIRST_LOGIN);
|
||||
element.setTextContent(ISO8601.toString(history.getFirstLogin()));
|
||||
historyElement.appendChild(element);
|
||||
}
|
||||
|
||||
if (!history.isLastLoginEmpty()) {
|
||||
Element element = doc.createElement(XML_LAST_LOGIN);
|
||||
element.setTextContent(ISO8601.toString(history.getLastLogin()));
|
||||
historyElement.appendChild(element);
|
||||
}
|
||||
|
||||
if (!history.isLastPasswordChangeEmpty()) {
|
||||
Element element = doc.createElement(XML_LAST_PASSWORD_CHANGE);
|
||||
element.setTextContent(ISO8601.toString(history.getLastPasswordChange()));
|
||||
historyElement.appendChild(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// write the container file to disk
|
||||
XmlHelper.writeDocument(doc, this.modelFile);
|
||||
}
|
||||
|
||||
private void writePassword(User user, Element userElement) {
|
||||
PasswordCrypt passwordCrypt = user.getPasswordCrypt();
|
||||
if (passwordCrypt == null)
|
||||
return;
|
||||
|
||||
String passwordString = passwordCrypt.buildPasswordString();
|
||||
if (passwordString != null) {
|
||||
userElement.setAttribute(XML_ATTR_PASSWORD, passwordString);
|
||||
} else {
|
||||
if (passwordCrypt.getPassword() != null)
|
||||
userElement.setAttribute(XML_ATTR_PASSWORD, toHexString(passwordCrypt.getPassword()));
|
||||
if (passwordCrypt.getSalt() != null)
|
||||
userElement.setAttribute(XML_ATTR_SALT, toHexString(passwordCrypt.getSalt()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,16 +15,11 @@
|
|||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.privilege.model.UserState;
|
||||
import li.strolch.privilege.model.internal.Group;
|
||||
import li.strolch.privilege.model.internal.PasswordCrypt;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -32,6 +27,11 @@ import org.xml.sax.Attributes;
|
|||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -58,9 +58,13 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equals(XML_USER)) {
|
||||
if (qName.equals(USER)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(UserParser.class)))
|
||||
throw new IllegalArgumentException("Previous User not closed!");
|
||||
this.buildersStack.push(new UserParser());
|
||||
} else if (qName.equals(XML_PROPERTIES)) {
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
if (this.buildersStack.stream().anyMatch(e -> e.getClass().equals(PropertyParser.class)))
|
||||
throw new IllegalArgumentException("Previous Properties not closed!");
|
||||
this.buildersStack.push(new PropertyParser());
|
||||
}
|
||||
|
||||
|
@ -81,9 +85,9 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||
|
||||
ElementParser elementParser = null;
|
||||
if (qName.equals(XML_USER)) {
|
||||
if (qName.equals(USER)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
} else if (qName.equals(XML_PROPERTIES)) {
|
||||
} else if (qName.equals(PROPERTIES)) {
|
||||
elementParser = this.buildersStack.pop();
|
||||
}
|
||||
|
||||
|
@ -122,12 +126,14 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
String lastname;
|
||||
UserState userState;
|
||||
Locale locale;
|
||||
final Set<String> groups;
|
||||
final Set<String> userRoles;
|
||||
Map<String, String> parameters;
|
||||
UserHistory history;
|
||||
boolean passwordChangeRequested;
|
||||
|
||||
public UserParser() {
|
||||
this.groups = new HashSet<>();
|
||||
this.userRoles = new HashSet<>();
|
||||
}
|
||||
|
||||
|
@ -136,15 +142,15 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
|
||||
this.text = new StringBuilder();
|
||||
|
||||
if (qName.equals(XML_USER)) {
|
||||
this.userId = attributes.getValue(XML_ATTR_USER_ID).trim();
|
||||
this.username = attributes.getValue(XML_ATTR_USERNAME).trim();
|
||||
if (qName.equals(USER)) {
|
||||
this.userId = attributes.getValue(ATTR_USER_ID).trim();
|
||||
this.username = attributes.getValue(ATTR_USERNAME).trim();
|
||||
|
||||
String password = attributes.getValue(XML_ATTR_PASSWORD);
|
||||
String salt = attributes.getValue(XML_ATTR_SALT);
|
||||
String password = attributes.getValue(ATTR_PASSWORD);
|
||||
String salt = attributes.getValue(ATTR_SALT);
|
||||
this.passwordCrypt = PasswordCrypt.parse(password, salt);
|
||||
} else if (qName.equals(XML_HISTORY)) {
|
||||
this.history = new UserHistory();
|
||||
} else if (qName.equals(HISTORY)) {
|
||||
this.history = UserHistory.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,40 +163,45 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
public void endElement(String uri, String localName, String qName) {
|
||||
|
||||
switch (qName) {
|
||||
case XML_FIRSTNAME -> this.firstName = this.text.toString().trim();
|
||||
case XML_LASTNAME -> this.lastname = this.text.toString().trim();
|
||||
case XML_STATE -> this.userState = UserState.valueOf(this.text.toString().trim());
|
||||
case XML_LOCALE -> this.locale = Locale.forLanguageTag(this.text.toString().trim());
|
||||
case XML_PASSWORD_CHANGE_REQUESTED ->
|
||||
this.passwordChangeRequested = Boolean.parseBoolean(this.text.toString().trim());
|
||||
case XML_FIRST_LOGIN -> this.history.setFirstLogin(ISO8601.parseToZdt(this.text.toString().trim()));
|
||||
case XML_LAST_LOGIN -> this.history.setLastLogin(ISO8601.parseToZdt(this.text.toString().trim()));
|
||||
case XML_LAST_PASSWORD_CHANGE ->
|
||||
this.history.setLastPasswordChange(ISO8601.parseToZdt(this.text.toString().trim()));
|
||||
case XML_ROLE -> this.userRoles.add(this.text.toString().trim());
|
||||
case XML_USER -> {
|
||||
case FIRSTNAME -> this.firstName = getText();
|
||||
case LASTNAME -> this.lastname = getText();
|
||||
case STATE -> this.userState = UserState.valueOf(getText());
|
||||
case LOCALE -> this.locale = Locale.forLanguageTag(getText());
|
||||
case PASSWORD_CHANGE_REQUESTED -> this.passwordChangeRequested = Boolean.parseBoolean(getText());
|
||||
case FIRST_LOGIN -> this.history = this.history.withFirstLogin(ISO8601.parseToZdt(getText()));
|
||||
case LAST_LOGIN -> this.history = this.history.withLastLogin(ISO8601.parseToZdt(getText()));
|
||||
case LAST_PASSWORD_CHANGE ->
|
||||
this.history = this.history.withLastPasswordChange(ISO8601.parseToZdt(getText()));
|
||||
case GROUP -> this.groups.add(getText());
|
||||
case ROLE -> this.userRoles.add(getText());
|
||||
case USER -> {
|
||||
if (this.history == null)
|
||||
this.history = new UserHistory();
|
||||
this.history = UserHistory.EMPTY;
|
||||
|
||||
User user = new User(this.userId, this.username, this.passwordCrypt, this.firstName, this.lastname,
|
||||
this.userState, this.userRoles, this.locale, this.parameters, this.passwordChangeRequested,
|
||||
this.history);
|
||||
this.userState, this.groups, this.userRoles, this.locale, this.parameters,
|
||||
this.passwordChangeRequested, this.history);
|
||||
|
||||
logger.info(MessageFormat.format("New User: {0}", user));
|
||||
String username = caseInsensitiveUsername ? user.getUsername().toLowerCase() : user.getUsername();
|
||||
users.put(username, user);
|
||||
}
|
||||
default -> {
|
||||
if (!(qName.equals(XML_ROLES) //
|
||||
|| qName.equals(XML_PARAMETER) //
|
||||
|| qName.equals(XML_HISTORY) //
|
||||
|| qName.equals(XML_PARAMETERS))) {
|
||||
if (!(qName.equals(ROLES) //
|
||||
|| qName.equals(GROUPS) //
|
||||
|| qName.equals(PARAMETER) //
|
||||
|| qName.equals(HISTORY) //
|
||||
|| qName.equals(PARAMETERS))) {
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getText() {
|
||||
return this.text.toString().trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyChild(ElementParser child) {
|
||||
if (child instanceof PropertyParser) {
|
||||
|
@ -198,29 +209,4 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class PropertyParser extends ElementParserAdapter {
|
||||
|
||||
// <Property name="organizationalUnit" value="Development" />
|
||||
|
||||
public final Map<String, String> parameterMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
|
||||
if (qName.equals(XML_PROPERTY)) {
|
||||
String key = attributes.getValue(XML_ATTR_NAME).trim();
|
||||
String value = attributes.getValue(XML_ATTR_VALUE).trim();
|
||||
this.parameterMap.put(key, value);
|
||||
} else {
|
||||
if (!qName.equals(XML_PROPERTIES)) {
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getParameterMap() {
|
||||
return this.parameterMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.privilege.xml;
|
||||
|
||||
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||
import li.strolch.privilege.model.internal.PasswordCrypt;
|
||||
import li.strolch.privilege.model.internal.User;
|
||||
import li.strolch.privilege.model.internal.UserHistory;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
import static li.strolch.privilege.helper.XmlHelper.*;
|
||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||
import static li.strolch.utils.helper.StringHelper.toHexString;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class PrivilegeUsersSaxWriter {
|
||||
|
||||
private final List<User> users;
|
||||
private final File modelFile;
|
||||
|
||||
public PrivilegeUsersSaxWriter(List<User> users, File modelFile) {
|
||||
this.users = users;
|
||||
this.modelFile = modelFile;
|
||||
}
|
||||
|
||||
public void write() throws IOException, XMLStreamException {
|
||||
|
||||
try (Writer ioWriter = new OutputStreamWriter(new FileOutputStream(this.modelFile), StandardCharsets.UTF_8)) {
|
||||
|
||||
IndentingXMLStreamWriter xmlWriter = openXmlStreamWriterDocument(ioWriter);
|
||||
xmlWriter.writeStartElement(USERS);
|
||||
|
||||
List<User> users = new ArrayList<>(this.users);
|
||||
users.sort(comparing(u -> u.getUsername().toLowerCase(Locale.ROOT)));
|
||||
for (User user : this.users) {
|
||||
|
||||
// start the user element
|
||||
xmlWriter.writeStartElement(USER);
|
||||
|
||||
xmlWriter.writeAttribute(ATTR_USER_ID, user.getUserId());
|
||||
xmlWriter.writeAttribute(ATTR_USERNAME, user.getUsername());
|
||||
writePassword(user, xmlWriter);
|
||||
|
||||
// add first name element
|
||||
if (isNotEmpty(user.getFirstname()))
|
||||
writeStringElement(xmlWriter, FIRSTNAME, user.getFirstname());
|
||||
|
||||
// add last name element
|
||||
if (isNotEmpty(user.getLastname()))
|
||||
writeStringElement(xmlWriter, LASTNAME, user.getLastname());
|
||||
|
||||
// add state element
|
||||
writeStringElement(xmlWriter, STATE, user.getUserState().toString());
|
||||
|
||||
// add locale element
|
||||
writeStringElement(xmlWriter, LOCALE, user.getLocale().toLanguageTag());
|
||||
|
||||
// add password change requested element
|
||||
if (user.isPasswordChangeRequested())
|
||||
writeStringElement(xmlWriter, PASSWORD_CHANGE_REQUESTED, "true");
|
||||
|
||||
// add all the group elements
|
||||
if (!user.getGroups().isEmpty()) {
|
||||
xmlWriter.writeStartElement(GROUPS);
|
||||
writeStringList(xmlWriter, GROUP, user.getGroups());
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// add all the role elements
|
||||
if (!user.getRoles().isEmpty()) {
|
||||
xmlWriter.writeStartElement(ROLES);
|
||||
writeStringList(xmlWriter, ROLE, user.getRoles());
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// add the parameters
|
||||
Map<String, String> properties = user.getProperties();
|
||||
if (!properties.isEmpty())
|
||||
writeStringMapElement(xmlWriter, properties, PROPERTIES, PROPERTY);
|
||||
|
||||
if (!user.isHistoryEmpty()) {
|
||||
UserHistory history = user.getHistory();
|
||||
xmlWriter.writeStartElement(HISTORY);
|
||||
|
||||
if (!history.isFirstLoginEmpty())
|
||||
writeStringElement(xmlWriter, FIRST_LOGIN, ISO8601.toString(history.getFirstLogin()));
|
||||
|
||||
if (!history.isLastLoginEmpty())
|
||||
writeStringElement(xmlWriter, LAST_LOGIN, ISO8601.toString(history.getLastLogin()));
|
||||
|
||||
if (!history.isLastPasswordChangeEmpty())
|
||||
writeStringElement(xmlWriter, LAST_PASSWORD_CHANGE,
|
||||
ISO8601.toString(history.getLastPasswordChange()));
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
// and now end
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void writePassword(User user, XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
|
||||
PasswordCrypt passwordCrypt = user.getPasswordCrypt();
|
||||
if (passwordCrypt == null)
|
||||
return;
|
||||
|
||||
String passwordString = passwordCrypt.buildPasswordString();
|
||||
if (passwordString != null) {
|
||||
xmlStreamWriter.writeAttribute(ATTR_PASSWORD, passwordString);
|
||||
} else {
|
||||
if (passwordCrypt.password() != null)
|
||||
xmlStreamWriter.writeAttribute(ATTR_PASSWORD, toHexString(passwordCrypt.password()));
|
||||
if (passwordCrypt.salt() != null)
|
||||
xmlStreamWriter.writeAttribute(ATTR_SALT, toHexString(passwordCrypt.salt()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package li.strolch.privilege.xml;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||
|
||||
class PropertyParser extends ElementParserAdapter {
|
||||
|
||||
// <Property name="organizationalUnit" value="Development" />
|
||||
|
||||
public final Map<String, String> parameterMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
|
||||
if (qName.equals(PROPERTY)) {
|
||||
String key = attributes.getValue(ATTR_NAME).trim();
|
||||
String value = attributes.getValue(ATTR_VALUE).trim();
|
||||
this.parameterMap.put(key, value);
|
||||
} else {
|
||||
if (!qName.equals(PROPERTIES)) {
|
||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getParameterMap() {
|
||||
return this.parameterMap;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ Privilege.privilegeNameEmpty=The PrivilegeName for the Restrictable is null or e
|
|||
Privilege.privilegeNull=Privilege may not be null\!
|
||||
Privilege.restrictableNull=Restrictable may not be null\!
|
||||
Privilege.noprivilege=No Privilege exists with name {0}
|
||||
Privilege.noprivilege.group=User {0} does not belong to group {1}
|
||||
Privilege.noprivilege.role=User {0} does not have the role {1}
|
||||
Privilege.noprivilege.user=User {0} does not have the privilege {1}
|
||||
Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
package li.strolch.privilege.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.helper.PrivilegeInitializer;
|
||||
|
@ -18,6 +11,13 @@ import org.junit.BeforeClass;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class AbstractPrivilegeTest {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(AbstractPrivilegeTest.class);
|
||||
|
@ -57,13 +57,14 @@ public class AbstractPrivilegeTest {
|
|||
}
|
||||
}
|
||||
|
||||
protected static void prepareConfigs(String dst, String configFilename, String usersFilename,
|
||||
protected static void prepareConfigs(String dst, String configFilename, String usersFilename, String groupsFilename,
|
||||
String rolesFilename) {
|
||||
try {
|
||||
File configPath = new File("src/test/resources/config");
|
||||
|
||||
File privilegeConfigFile = new File(configPath, configFilename);
|
||||
File privilegeUsersFile = new File(configPath, usersFilename);
|
||||
File privilegeGroupsFile = new File(configPath, groupsFilename);
|
||||
File privilegeRolesFile = new File(configPath, rolesFilename);
|
||||
|
||||
File targetPath = new File("target/" + dst);
|
||||
|
@ -72,6 +73,7 @@ public class AbstractPrivilegeTest {
|
|||
|
||||
File dstConfig = new File(targetPath, configFilename);
|
||||
File dstUsers = new File(targetPath, usersFilename);
|
||||
File dstGroups = new File(targetPath, groupsFilename);
|
||||
File dstRoles = new File(targetPath, rolesFilename);
|
||||
|
||||
// write config
|
||||
|
@ -81,6 +83,7 @@ public class AbstractPrivilegeTest {
|
|||
|
||||
// copy model
|
||||
Files.copy(privilegeUsersFile.toPath(), dstUsers.toPath());
|
||||
Files.copy(privilegeGroupsFile.toPath(), dstGroups.toPath());
|
||||
Files.copy(privilegeRolesFile.toPath(), dstRoles.toPath());
|
||||
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -20,9 +20,9 @@ public class CryptTest {
|
|||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
Map<String, String> parameterMap = new HashMap<>();
|
||||
parameterMap.put(XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||
parameterMap.put(XML_PARAM_HASH_ITERATIONS, "" + DEFAULT_SMALL_ITERATIONS);
|
||||
parameterMap.put(XML_PARAM_HASH_KEY_LENGTH, "" + DEFAULT_KEY_LENGTH);
|
||||
parameterMap.put(PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||
parameterMap.put(PARAM_HASH_ITERATIONS, "" + DEFAULT_SMALL_ITERATIONS);
|
||||
parameterMap.put(PARAM_HASH_KEY_LENGTH, "" + DEFAULT_KEY_LENGTH);
|
||||
|
||||
encryptionHandler = new DefaultEncryptionHandler();
|
||||
encryptionHandler.initialize(parameterMap);
|
||||
|
@ -41,7 +41,7 @@ public class CryptTest {
|
|||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, salt, "PBKDF2WithHmacSHA512", 100000,
|
||||
256);
|
||||
|
||||
assertArrayEquals(passwordCrypt.getPassword(), parsedCryptHash.getPassword());
|
||||
assertArrayEquals(passwordCrypt.password(), parsedCryptHash.password());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -53,9 +53,9 @@ public class CryptTest {
|
|||
assertNotNull(parsedCryptHash);
|
||||
|
||||
char[] password = "admin".toCharArray();
|
||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, parsedCryptHash.getSalt(),
|
||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, parsedCryptHash.salt(),
|
||||
"PBKDF2WithHmacSHA512", 100000, 256);
|
||||
|
||||
assertArrayEquals(passwordCrypt.getPassword(), parsedCryptHash.getPassword());
|
||||
assertArrayEquals(passwordCrypt.password(), parsedCryptHash.password());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class PersistSessionsTest extends AbstractPrivilegeTest {
|
|||
public static void init() {
|
||||
removeConfigs(PersistSessionsTest.class.getSimpleName());
|
||||
prepareConfigs(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||
"PrivilegeRoles.xml");
|
||||
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
|
@ -15,14 +15,16 @@
|
|||
*/
|
||||
package li.strolch.privilege.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -32,7 +34,7 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
|||
public static void init() {
|
||||
removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName());
|
||||
prepareConfigs(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml",
|
||||
"PrivilegeUsersMerge.xml", "PrivilegeRolesMerge.xml");
|
||||
"PrivilegeUsersMerge.xml", "PrivilegeGroupsMerge.xml", "PrivilegeRolesMerge.xml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -49,7 +51,16 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
|||
public void shouldMergePrivileges1() {
|
||||
try {
|
||||
login("userA", "admin".toCharArray());
|
||||
IPrivilege privilege = this.ctx.getPrivilege("Foo");
|
||||
assertEquals(Set.of(), this.ctx.getUserRep().getGroups());
|
||||
assertFalse(this.ctx.hasGroup("GroupA1"));
|
||||
assertFalse(this.ctx.hasGroup("GroupA2"));
|
||||
assertEquals(Set.of("RoleA1", "RoleA2"), this.ctx.getUserRep().getRoles());
|
||||
assertTrue(this.ctx.hasRole("RoleA1"));
|
||||
assertTrue(this.ctx.hasRole("RoleA2"));
|
||||
assertFalse(this.ctx.hasRole("RoleB2"));
|
||||
assertNull(this.ctx.getUserRep().getLocation());
|
||||
assertEquals(Set.of(), this.ctx.getUserRep().getPropertyKeySet());
|
||||
Privilege privilege = this.ctx.getPrivilege("Foo");
|
||||
assertTrue(privilege.isAllAllowed());
|
||||
assertTrue(privilege.getAllowList().isEmpty());
|
||||
assertTrue(privilege.getDenyList().isEmpty());
|
||||
|
@ -63,7 +74,16 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
|||
public void shouldMergePrivileges2() {
|
||||
try {
|
||||
login("userB", "admin".toCharArray());
|
||||
IPrivilege privilege = this.ctx.getPrivilege("Bar");
|
||||
assertEquals(Set.of(), this.ctx.getUserRep().getGroups());
|
||||
assertFalse(this.ctx.hasGroup("GroupB1"));
|
||||
assertFalse(this.ctx.hasGroup("GroupB2"));
|
||||
assertEquals(Set.of("RoleB1", "RoleB2"), this.ctx.getUserRep().getRoles());
|
||||
assertTrue(this.ctx.hasRole("RoleB1"));
|
||||
assertTrue(this.ctx.hasRole("RoleB2"));
|
||||
assertFalse(this.ctx.hasRole("RoleA2"));
|
||||
assertNull(this.ctx.getUserRep().getLocation());
|
||||
assertEquals(Set.of(), this.ctx.getUserRep().getPropertyKeySet());
|
||||
Privilege privilege = this.ctx.getPrivilege("Bar");
|
||||
assertFalse(privilege.isAllAllowed());
|
||||
assertEquals(2, privilege.getAllowList().size());
|
||||
assertEquals(2, privilege.getDenyList().size());
|
||||
|
@ -71,4 +91,53 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
|||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMergePrivileges3() {
|
||||
try {
|
||||
login("userC", "admin".toCharArray());
|
||||
assertEquals(Set.of("GroupA1", "GroupA2"), this.ctx.getUserRep().getGroups());
|
||||
assertTrue(this.ctx.hasGroup("GroupA1"));
|
||||
assertTrue(this.ctx.hasGroup("GroupA2"));
|
||||
assertFalse(this.ctx.hasGroup("GroupB2"));
|
||||
assertEquals(Set.of("RoleA1", "RoleA2"), this.ctx.getUserRep().getRoles());
|
||||
assertTrue(this.ctx.hasRole("RoleA1"));
|
||||
assertTrue(this.ctx.hasRole("RoleA2"));
|
||||
assertFalse(this.ctx.hasRole("RoleB2"));
|
||||
assertEquals("LocationA2", this.ctx.getUserRep().getLocation());
|
||||
assertEquals(Set.of("location"), this.ctx.getUserRep().getPropertyKeySet());
|
||||
Privilege privilege = this.ctx.getPrivilege("Foo");
|
||||
assertTrue(privilege.isAllAllowed());
|
||||
assertTrue(privilege.getAllowList().isEmpty());
|
||||
assertTrue(privilege.getDenyList().isEmpty());
|
||||
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMergePrivileges4() {
|
||||
try {
|
||||
login("userD", "admin".toCharArray());
|
||||
assertEquals(Set.of("GroupB1", "GroupB2"), this.ctx.getUserRep().getGroups());
|
||||
assertTrue(this.ctx.hasGroup("GroupB1"));
|
||||
assertTrue(this.ctx.hasGroup("GroupB2"));
|
||||
assertFalse(this.ctx.hasGroup("GroupA2"));
|
||||
assertEquals(Set.of("RoleB1", "RoleB2"), this.ctx.getUserRep().getRoles());
|
||||
assertTrue(this.ctx.hasRole("RoleB1"));
|
||||
assertTrue(this.ctx.hasRole("RoleB2"));
|
||||
assertFalse(this.ctx.hasRole("RoleA2"));
|
||||
assertEquals("LocationB2", this.ctx.getUserRep().getLocation());
|
||||
assertEquals(Set.of("location"), this.ctx.getUserRep().getPropertyKeySet());
|
||||
Privilege privilege = this.ctx.getPrivilege("Bar");
|
||||
assertFalse(privilege.isAllAllowed());
|
||||
assertEquals(2, privilege.getAllowList().size());
|
||||
assertEquals(2, privilege.getDenyList().size());
|
||||
assertEquals(Set.of("allow1", "allow2"), privilege.getAllowList());
|
||||
assertEquals(Set.of("deny1", "deny2"), privilege.getDenyList());
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,6 @@
|
|||
*/
|
||||
package li.strolch.privilege.test;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.InvalidCredentialsException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
|
@ -41,9 +35,15 @@ import org.junit.Test;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* JUnit for performing Privilege tests. This JUnit is by no means complete, but checks the bare minimum.br />
|
||||
*
|
||||
* <p>
|
||||
* TODO add more tests, especially with deny and allow lists
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -77,12 +77,12 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
public static void init() {
|
||||
removeConfigs(PrivilegeTest.class.getSimpleName());
|
||||
prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||
"PrivilegeRoles.xml");
|
||||
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() {
|
||||
removeConfigs(PrivilegeTest.class.getSimpleName());
|
||||
//removeConfigs(PrivilegeTest.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -137,7 +137,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
try {
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
|
||||
RoleRep roleRep = new RoleRep(ROLE_TEMP, new ArrayList<>());
|
||||
RoleRep roleRep = new RoleRep(ROLE_TEMP, Map.of());
|
||||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRole(certificate, roleRep);
|
||||
|
@ -209,7 +209,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
}
|
||||
});
|
||||
MatcherAssert.assertThat(exception.getMessage(), containsString(
|
||||
"User system_admin2 does not have the privilege li.strolch.privilege.handler.SystemAction with value li.strolch.privilege.test.model.TestSystemUserActionDeny needed for Restrictable li.strolch.privilege.test.model.TestSystemUserActionDeny"));
|
||||
"User system_admin2 does not have the privilege li.strolch.privilege.handler.SystemAction with value " +
|
||||
"li.strolch.privilege.test.model.TestSystemUserActionDeny needed for Restrictable " +
|
||||
"li.strolch.privilege.test.model.TestSystemUserActionDeny"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,9 +253,12 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
assertNotEquals("The", user.getFirstname());
|
||||
assertNotEquals("Admin", user.getLastname());
|
||||
|
||||
// let's add a new user bob
|
||||
UserRep userRep = new UserRep(null, ADMIN, "The", "Admin", null, null, null, null, null);
|
||||
this.privilegeHandler.updateUser(certificate, userRep);
|
||||
// set new name
|
||||
user.setFirstname("The");
|
||||
user.setLastname("Admin");
|
||||
|
||||
// update user
|
||||
this.privilegeHandler.updateUser(certificate, user, null);
|
||||
|
||||
user = this.privilegeHandler.getUser(certificate, ADMIN);
|
||||
assertEquals("The", user.getFirstname());
|
||||
|
@ -273,8 +278,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
// let's add a new user bob
|
||||
UserRep userRep = new UserRep(null, BOB, null, null, null, null, null, null, null);
|
||||
this.privilegeHandler.updateUser(certificate, userRep);
|
||||
UserRep userRep = new UserRep(BOB, BOB, "Bob", "Anderson", UserState.ENABLED,
|
||||
Set.of("AppUserLocationA"), null, null, null, null);
|
||||
this.privilegeHandler.updateUser(certificate, userRep, null);
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
|
@ -282,25 +288,6 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
MatcherAssert.assertThat(exception.getMessage(), containsString("User bob does not exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailUpdateAdminNoChanges() {
|
||||
PrivilegeException exception = assertThrows(PrivilegeException.class, () -> {
|
||||
try {
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
// let's add a new user bob
|
||||
UserRep userRep = new UserRep(null, ADMIN, null, null, null, null, null, null, null);
|
||||
this.privilegeHandler.updateUser(certificate, userRep);
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
});
|
||||
MatcherAssert.assertThat(exception.getMessage(),
|
||||
containsString("All updateable fields are empty for update of user admin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryUsers() {
|
||||
try {
|
||||
|
@ -308,7 +295,24 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
UserRep selectorRep = new UserRep(null, ADMIN, null, null, null, null, null, null, null);
|
||||
UserRep selectorRep = new UserRep(null, ADMIN, null, null, null, null, null, null, null, null);
|
||||
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||
assertEquals(1, users.size());
|
||||
assertEquals(ADMIN, users.get(0).getUsername());
|
||||
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryUsersByGroups() {
|
||||
try {
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
UserRep selectorRep = new UserRep(null, null, null, null, null, Set.of("GroupA"), null, null, null, null);
|
||||
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||
assertEquals(1, users.size());
|
||||
assertEquals(ADMIN, users.get(0).getUsername());
|
||||
|
@ -325,8 +329,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
UserRep selectorRep = new UserRep(null, null, null, null, null,
|
||||
new HashSet<>(Collections.singletonList("PrivilegeAdmin")), null, null, null);
|
||||
UserRep selectorRep = new UserRep(null, null, null, null, null, null, Set.of("PrivilegeAdmin"), null, null,
|
||||
null);
|
||||
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||
assertEquals(2, users.size());
|
||||
assertEquals(ADMIN, users.get(0).getUsername());
|
||||
|
@ -344,7 +348,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
Certificate certificate = this.ctx.getCertificate();
|
||||
|
||||
UserRep selectorRep = new UserRep(null, null, null, null, null,
|
||||
new HashSet<>(Collections.singletonList(ROLE_TEMP)), null, null, null);
|
||||
new HashSet<>(Collections.singletonList(ROLE_TEMP)), null, null, null, null);
|
||||
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||
assertEquals(0, users.size());
|
||||
|
||||
|
@ -360,8 +364,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege",
|
||||
true, Collections.emptySet(), Collections.emptySet());
|
||||
this.privilegeHandler.addOrReplacePrivilegeOnRole(certificate, ROLE_APP_USER, privilegeRep);
|
||||
true, Set.of(), Set.of());
|
||||
RoleRep role = this.privilegeHandler.getRole(certificate, ROLE_APP_USER);
|
||||
role.addPrivilege(privilegeRep);
|
||||
this.privilegeHandler.replaceRole(certificate, role);
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
|
@ -375,8 +381,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
try {
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY);
|
||||
this.privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY2);
|
||||
UserRep user = this.privilegeHandler.getUser(certificate, ADMIN);
|
||||
user.addRole(ROLE_MY);
|
||||
user.addRole(ROLE_MY2);
|
||||
this.privilegeHandler.updateUser(certificate, user, null);
|
||||
} finally {
|
||||
logout();
|
||||
}
|
||||
|
@ -540,15 +548,21 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
|
||||
PrivilegeRep passwordRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD,
|
||||
PRIVILEGE_USER_ACCESS, false, Collections.emptySet(), Collections.emptySet());
|
||||
PRIVILEGE_USER_ACCESS, false, Set.of(), Set.of());
|
||||
PrivilegeRep localeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE, PRIVILEGE_USER_ACCESS,
|
||||
false, Collections.emptySet(), Collections.emptySet());
|
||||
false, Set.of(), Set.of());
|
||||
|
||||
RoleRep roleRep = new RoleRep(ROLE_CHANGE_PW, Arrays.asList(passwordRep, localeRep));
|
||||
Map<String, PrivilegeRep> privileges = new HashMap<>();
|
||||
privileges.put(passwordRep.getName(), passwordRep);
|
||||
privileges.put(localeRep.getName(), localeRep);
|
||||
RoleRep roleRep = new RoleRep(ROLE_CHANGE_PW, privileges);
|
||||
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRole(certificate, roleRep);
|
||||
this.privilegeHandler.addRoleToUser(certificate, TED, ROLE_CHANGE_PW);
|
||||
|
||||
UserRep ted = this.privilegeHandler.getUser(certificate, TED);
|
||||
ted.addRole(ROLE_CHANGE_PW);
|
||||
this.privilegeHandler.updateUser(certificate, ted, null);
|
||||
logger.info("Added " + ROLE_CHANGE_PW + " to " + TED);
|
||||
this.privilegeHandler.persist(certificate);
|
||||
} finally {
|
||||
|
@ -574,7 +588,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
// testAddAppRoleToBob
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRoleToUser(certificate, BOB, ROLE_APP_USER);
|
||||
UserRep bob = this.privilegeHandler.getUser(certificate, BOB);
|
||||
bob.addRole(ROLE_APP_USER);
|
||||
this.privilegeHandler.updateUser(certificate, bob, null);
|
||||
logger.info("Added " + ROLE_APP_USER + " to " + BOB);
|
||||
this.privilegeHandler.persist(certificate);
|
||||
} finally {
|
||||
|
@ -593,7 +609,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
this.ctx.validateAction(restrictable);
|
||||
fail("Should fail as bob does not have role app");
|
||||
} catch (AccessDeniedException e) {
|
||||
String msg = "User bob does not have the privilege li.strolch.privilege.test.model.TestRestrictable needed for Restrictable li.strolch.privilege.test.model.TestRestrictable and value li.strolch.privilege.test.model.TestRestrictable";
|
||||
String msg =
|
||||
"User bob does not have the privilege li.strolch.privilege.test.model.TestRestrictable needed for " +
|
||||
"Restrictable li.strolch.privilege.test.model.TestRestrictable and value " +
|
||||
"li.strolch.privilege.test.model.TestRestrictable";
|
||||
assertEquals(msg, e.getLocalizedMessage());
|
||||
} finally {
|
||||
logout();
|
||||
|
@ -656,7 +675,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
// let's add a new user ted
|
||||
HashSet<String> roles = new HashSet<>();
|
||||
roles.add(ROLE_USER);
|
||||
userRep = new UserRep(null, TED, "Ted", "Newman", UserState.ENABLED, roles, null, new HashMap<>(), null);
|
||||
userRep = new UserRep(null, TED, "Ted", "Newman", UserState.ENABLED, Set.of(), roles, null, new HashMap<>(),
|
||||
null);
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||
logger.info("Added user " + TED);
|
||||
|
@ -671,7 +691,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
// testAddAdminRoleToBob
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRoleToUser(certificate, BOB, ROLE_PRIVILEGE_ADMIN);
|
||||
UserRep bob = this.privilegeHandler.getUser(certificate, BOB);
|
||||
bob.addRole(ROLE_PRIVILEGE_ADMIN);
|
||||
this.privilegeHandler.updateUser(certificate, bob, null);
|
||||
logger.info("Added " + ROLE_PRIVILEGE_ADMIN + " to " + ADMIN);
|
||||
this.privilegeHandler.persist(certificate);
|
||||
} finally {
|
||||
|
@ -688,14 +710,14 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
// auth as Bob
|
||||
login(BOB, ArraysHelper.copyOf(PASS_BOB));
|
||||
// let's add a new user Ted
|
||||
userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, new HashSet<>(), null,
|
||||
userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, Set.of(), Set.of(), null,
|
||||
new HashMap<>(), null);
|
||||
certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||
fail("User bob may not add a user as bob does not have admin rights!");
|
||||
} catch (PrivilegeException e) {
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"),
|
||||
BOB, PrivilegeHandler.PRIVILEGE_ADD_USER);
|
||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), BOB,
|
||||
PrivilegeHandler.PRIVILEGE_ADD_USER);
|
||||
assertEquals(msg, e.getMessage());
|
||||
} finally {
|
||||
logout();
|
||||
|
@ -716,7 +738,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
// testAddRoleUserToBob
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRoleToUser(certificate, BOB, ROLE_USER);
|
||||
UserRep bob = this.privilegeHandler.getUser(certificate, BOB);
|
||||
bob.addRole(ROLE_USER);
|
||||
this.privilegeHandler.updateUser(certificate, bob, null);
|
||||
this.privilegeHandler.persist(certificate);
|
||||
logout();
|
||||
} finally {
|
||||
|
@ -728,7 +752,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
try {
|
||||
// add role user
|
||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
RoleRep roleRep = new RoleRep(ROLE_USER, new ArrayList<>());
|
||||
RoleRep roleRep = new RoleRep(ROLE_USER, Map.of());
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addRole(certificate, roleRep);
|
||||
this.privilegeHandler.persist(certificate);
|
||||
|
@ -768,8 +792,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
|
||||
// let's add a new user bob
|
||||
UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW,
|
||||
new HashSet<>(Collections.singletonList(ROLE_MY)), null, new HashMap<>(), null);
|
||||
UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW, Set.of(), Set.of(ROLE_MY), null,
|
||||
new HashMap<>(), null);
|
||||
Certificate certificate = this.ctx.getCertificate();
|
||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||
logger.info("Added user " + BOB);
|
||||
|
|
|
@ -17,7 +17,7 @@ public class SsoHandlerTest extends AbstractPrivilegeTest {
|
|||
public static void init() {
|
||||
removeConfigs(SsoHandlerTest.class.getSimpleName());
|
||||
prepareConfigs(SsoHandlerTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||
"PrivilegeRoles.xml");
|
||||
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -39,6 +39,7 @@ public class SsoHandlerTest extends AbstractPrivilegeTest {
|
|||
data.put("username", "admin");
|
||||
data.put("firstName", "Admin");
|
||||
data.put("lastName", "Istrator");
|
||||
data.put("groups", "AppUserLocationA");
|
||||
data.put("roles", "PrivilegeAdmin, AppUser");
|
||||
|
||||
// auth
|
||||
|
|
|
@ -4,14 +4,17 @@ import static li.strolch.privilege.test.XmlTest.SRC_TEST;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import li.strolch.privilege.helper.WriteRolesFileHelper;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
public class WriteRolesFileHelperTest {
|
||||
|
||||
@Test
|
||||
public void shouldReadAndWriteRolesFile() {
|
||||
public void shouldReadAndWriteRolesFile() throws XMLStreamException, IOException {
|
||||
|
||||
String src = SRC_TEST + "PrivilegeRoles.xml";
|
||||
String dst = "target/WriteRolesFileHelperTest_roles.xml";
|
||||
|
@ -19,7 +22,7 @@ public class WriteRolesFileHelperTest {
|
|||
if (new File(dst).exists() && !new File(dst).delete())
|
||||
throw new IllegalStateException("Could not delete file " + dst);
|
||||
|
||||
WriteRolesFileHelper.main(new String[] { src, dst });
|
||||
WriteRolesFileHelper.main(new String[]{src, dst});
|
||||
|
||||
assertTrue(new File(dst).exists());
|
||||
}
|
||||
|
|
|
@ -15,11 +15,8 @@
|
|||
*/
|
||||
package li.strolch.privilege.test;
|
||||
|
||||
import li.strolch.privilege.handler.DefaultEncryptionHandler;
|
||||
import li.strolch.privilege.handler.MailUserChallengeHandler;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
import li.strolch.privilege.handler.XmlPersistenceHandler;
|
||||
import li.strolch.privilege.model.IPrivilege;
|
||||
import li.strolch.privilege.handler.*;
|
||||
import li.strolch.privilege.model.Privilege;
|
||||
import li.strolch.privilege.model.UserState;
|
||||
import li.strolch.privilege.model.internal.*;
|
||||
import li.strolch.privilege.test.model.DummySsoHandler;
|
||||
|
@ -33,7 +30,10 @@ import org.junit.Test;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
@ -80,6 +80,11 @@ public class XmlTest {
|
|||
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
tmpFile = new File(TARGET_TEST + "PrivilegeGroupsTest.xml");
|
||||
if (tmpFile.exists() && !tmpFile.delete()) {
|
||||
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
tmpFile = new File(TARGET_TEST + "PrivilegeRolesTest.xml");
|
||||
if (tmpFile.exists() && !tmpFile.delete()) {
|
||||
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
|
||||
|
@ -115,7 +120,7 @@ public class XmlTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void canWriteConfig() {
|
||||
public void canWriteConfig() throws XMLStreamException, IOException {
|
||||
|
||||
Map<String, String> parameterMap = new HashMap<>();
|
||||
Map<String, String> encryptionHandlerParameterMap = new HashMap<>();
|
||||
|
@ -128,6 +133,7 @@ public class XmlTest {
|
|||
|
||||
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
|
||||
containerModel.setParameterMap(parameterMap);
|
||||
containerModel.setPrivilegeHandlerClassName(DefaultPrivilegeHandler.class.getName());
|
||||
containerModel.setEncryptionHandlerClassName(DefaultEncryptionHandler.class.getName());
|
||||
containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap);
|
||||
containerModel.setPersistenceHandlerClassName(XmlPersistenceHandler.class.getName());
|
||||
|
@ -138,11 +144,38 @@ public class XmlTest {
|
|||
containerModel.addPolicy("DefaultPrivilege", "li.strolch.privilege.policy.DefaultPrivilege");
|
||||
|
||||
File configFile = new File(TARGET_TEST + "PrivilegeTest.xml");
|
||||
PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile);
|
||||
PrivilegeConfigSaxWriter configSaxWriter = new PrivilegeConfigSaxWriter(containerModel, configFile);
|
||||
configSaxWriter.write();
|
||||
|
||||
String fileHash = StringHelper.toHexString(FileHelper.hashFileSha256(configFile));
|
||||
assertEquals("dcb6b3ed7198e0a7c88bf5c61c0bd6f0d684415f2a2f29429879edc6bc795f06", fileHash);
|
||||
String expected = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
<Container>
|
||||
<Parameters>
|
||||
<Parameter name="autoPersistOnPasswordChange" value="true"/>
|
||||
</Parameters>
|
||||
<PrivilegeHandler class="li.strolch.privilege.handler.DefaultPrivilegeHandler"/>
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<Parameter name="hashAlgorithm" value="SHA-256"/>
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="basePath" value="target/test/"/>
|
||||
<Parameter name="modelXmlFile" value="PrivilegeModel.xml"/>
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.MailUserChallengeHandler"/>
|
||||
<SsoHandler class="li.strolch.privilege.test.model.DummySsoHandler"/>
|
||||
</Container>
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
|
||||
</Policies>
|
||||
</Privilege>
|
||||
""";
|
||||
|
||||
assertEquals(expected, Files.readString(configFile.toPath()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -166,12 +199,13 @@ public class XmlTest {
|
|||
assertEquals("1", admin.getUserId());
|
||||
assertEquals("admin", admin.getUsername());
|
||||
assertEquals("cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344",
|
||||
StringHelper.toHexString(admin.getPasswordCrypt().getPassword()));
|
||||
assertEquals("61646d696e", StringHelper.toHexString(admin.getPasswordCrypt().getSalt()));
|
||||
StringHelper.toHexString(admin.getPasswordCrypt().password()));
|
||||
assertEquals("61646d696e", StringHelper.toHexString(admin.getPasswordCrypt().salt()));
|
||||
assertEquals("Application", admin.getFirstname());
|
||||
assertEquals("Administrator", admin.getLastname());
|
||||
assertEquals(UserState.ENABLED, admin.getUserState());
|
||||
assertEquals("en-GB", admin.getLocale().toLanguageTag());
|
||||
assertEquals(Set.of("GroupA"), admin.getGroups());
|
||||
MatcherAssert.assertThat(admin.getRoles(), containsInAnyOrder("PrivilegeAdmin", "AppUser"));
|
||||
Map<String, String> properties = admin.getProperties();
|
||||
assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet());
|
||||
|
@ -187,8 +221,54 @@ public class XmlTest {
|
|||
assertEquals("Administrator", systemAdmin.getLastname());
|
||||
assertEquals(UserState.SYSTEM, systemAdmin.getUserState());
|
||||
assertEquals("en-GB", systemAdmin.getLocale().toLanguageTag());
|
||||
assertEquals(Set.of(), systemAdmin.getGroups());
|
||||
MatcherAssert.assertThat(systemAdmin.getRoles(), containsInAnyOrder("system_admin_privileges"));
|
||||
assertTrue(systemAdmin.getProperties().isEmpty());
|
||||
|
||||
// admin2
|
||||
User admin2 = findUser("admin2", users);
|
||||
assertEquals("1", admin2.getUserId());
|
||||
assertEquals("admin2", admin2.getUsername());
|
||||
assertEquals("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
|
||||
StringHelper.toHexString(admin2.getPasswordCrypt().password()));
|
||||
assertEquals("Application", admin2.getFirstname());
|
||||
assertEquals("Administrator", admin2.getLastname());
|
||||
assertEquals(UserState.ENABLED, admin2.getUserState());
|
||||
assertEquals("en-GB", admin2.getLocale().toLanguageTag());
|
||||
MatcherAssert.assertThat(admin2.getGroups(), containsInAnyOrder("AppUserLocationA"));
|
||||
MatcherAssert.assertThat(admin2.getRoles(), containsInAnyOrder("PrivilegeAdmin"));
|
||||
properties = admin2.getProperties();
|
||||
assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet());
|
||||
assertEquals("eitchnet.ch", properties.get("organization"));
|
||||
assertEquals("Development", properties.get("organizationalUnit"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canReadGroups() {
|
||||
|
||||
PrivilegeGroupsSaxReader xmlHandler = new PrivilegeGroupsSaxReader();
|
||||
File xmlFile = new File(SRC_TEST + "PrivilegeGroups.xml");
|
||||
XmlHelper.parseDocument(xmlFile, xmlHandler);
|
||||
|
||||
Map<String, Group> groups = xmlHandler.getGroups();
|
||||
assertNotNull(groups);
|
||||
|
||||
assertEquals(2, groups.size());
|
||||
|
||||
// group AppUserLocationA
|
||||
Group group = groups.get("AppUserLocationA");
|
||||
assertEquals("AppUserLocationA", group.name());
|
||||
MatcherAssert.assertThat(group.roles(), containsInAnyOrder("AppUser", "ModelAccessor", "UserPrivileges"));
|
||||
Map<String, String> properties = group.getProperties();
|
||||
assertEquals(new HashSet<>(List.of("location")), properties.keySet());
|
||||
assertEquals("LocationA", properties.get("location"));
|
||||
|
||||
group = groups.get("GroupA");
|
||||
assertEquals("GroupA", group.name());
|
||||
properties = group.getProperties();
|
||||
assertTrue(properties.isEmpty());
|
||||
assertTrue(group.roles().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,23 +292,22 @@ public class XmlTest {
|
|||
// PrivilegeAdmin
|
||||
Role privilegeAdmin = findRole("PrivilegeAdmin", roles);
|
||||
assertEquals("PrivilegeAdmin", privilegeAdmin.getName());
|
||||
assertEquals(18, privilegeAdmin.getPrivilegeNames().size());
|
||||
IPrivilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION);
|
||||
assertEquals(16, privilegeAdmin.getPrivilegeNames().size());
|
||||
Privilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION);
|
||||
assertFalse(privilegeAction.isAllAllowed());
|
||||
assertEquals(5, privilegeAction.getAllowList().size());
|
||||
assertEquals(0, privilegeAction.getDenyList().size());
|
||||
assertEquals("DefaultPrivilege", privilegeAction.getPolicy());
|
||||
|
||||
IPrivilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE);
|
||||
Privilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE);
|
||||
assertTrue(privilegeAddRole.isAllAllowed());
|
||||
assertEquals(0, privilegeAddRole.getAllowList().size());
|
||||
assertEquals(0, privilegeAddRole.getDenyList().size());
|
||||
|
||||
IPrivilege privilegeRemRoleFromUser = privilegeAdmin.getPrivilege(
|
||||
PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER);
|
||||
assertTrue(privilegeRemRoleFromUser.isAllAllowed());
|
||||
assertEquals(0, privilegeRemRoleFromUser.getAllowList().size());
|
||||
assertEquals(0, privilegeRemRoleFromUser.getDenyList().size());
|
||||
Privilege privilegeRemRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_REMOVE_ROLE);
|
||||
assertTrue(privilegeRemRole.isAllAllowed());
|
||||
assertEquals(0, privilegeRemRole.getAllowList().size());
|
||||
assertEquals(0, privilegeRemRole.getDenyList().size());
|
||||
|
||||
// AppUser
|
||||
Role appUser = findRole("AppUser", roles);
|
||||
|
@ -236,7 +315,7 @@ public class XmlTest {
|
|||
assertEquals(new HashSet<>(Collections.singletonList("li.strolch.privilege.test.model.TestRestrictable")),
|
||||
appUser.getPrivilegeNames());
|
||||
|
||||
IPrivilege testRestrictable = appUser.getPrivilege("li.strolch.privilege.test.model.TestRestrictable");
|
||||
Privilege testRestrictable = appUser.getPrivilege("li.strolch.privilege.test.model.TestRestrictable");
|
||||
assertEquals("li.strolch.privilege.test.model.TestRestrictable", testRestrictable.getName());
|
||||
assertEquals("DefaultPrivilege", testRestrictable.getPolicy());
|
||||
assertTrue(testRestrictable.isAllAllowed());
|
||||
|
@ -251,7 +330,7 @@ public class XmlTest {
|
|||
containsInAnyOrder("li.strolch.privilege.handler.SystemAction",
|
||||
"li.strolch.privilege.test.model.TestSystemRestrictable"));
|
||||
|
||||
IPrivilege testSystemUserAction = systemAdminPrivileges.getPrivilege(
|
||||
Privilege testSystemUserAction = systemAdminPrivileges.getPrivilege(
|
||||
"li.strolch.privilege.handler.SystemAction");
|
||||
assertEquals("li.strolch.privilege.handler.SystemAction", testSystemUserAction.getName());
|
||||
assertEquals("DefaultPrivilege", testSystemUserAction.getPolicy());
|
||||
|
@ -259,7 +338,7 @@ public class XmlTest {
|
|||
assertEquals(1, testSystemUserAction.getAllowList().size());
|
||||
assertEquals(1, testSystemUserAction.getDenyList().size());
|
||||
|
||||
IPrivilege testSystemRestrictable = systemAdminPrivileges.getPrivilege(
|
||||
Privilege testSystemRestrictable = systemAdminPrivileges.getPrivilege(
|
||||
"li.strolch.privilege.test.model.TestSystemRestrictable");
|
||||
assertEquals("li.strolch.privilege.test.model.TestSystemRestrictable", testSystemRestrictable.getName());
|
||||
assertEquals("DefaultPrivilege", testSystemRestrictable.getPolicy());
|
||||
|
@ -274,7 +353,7 @@ public class XmlTest {
|
|||
MatcherAssert.assertThat(restrictedRole.getPrivilegeNames(),
|
||||
containsInAnyOrder("li.strolch.privilege.handler.SystemAction"));
|
||||
|
||||
IPrivilege testSystemUserAction2 = restrictedRole.getPrivilege("li.strolch.privilege.handler.SystemAction");
|
||||
Privilege testSystemUserAction2 = restrictedRole.getPrivilege("li.strolch.privilege.handler.SystemAction");
|
||||
assertEquals("li.strolch.privilege.handler.SystemAction", testSystemUserAction2.getName());
|
||||
assertEquals("DefaultPrivilege", testSystemUserAction2.getPolicy());
|
||||
assertFalse(testSystemUserAction2.isAllAllowed());
|
||||
|
@ -295,36 +374,42 @@ public class XmlTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void canWriteUsers() {
|
||||
public void canWriteUsers() throws XMLStreamException, IOException {
|
||||
|
||||
Map<String, String> propertyMap;
|
||||
Set<String> groups;
|
||||
Set<String> userRoles;
|
||||
|
||||
List<User> users = new ArrayList<>();
|
||||
propertyMap = new HashMap<>();
|
||||
propertyMap.put("prop1", "value1");
|
||||
groups = new HashSet<>();
|
||||
groups.add("group1");
|
||||
userRoles = new HashSet<>();
|
||||
userRoles.add("role1");
|
||||
UserHistory history = new UserHistory();
|
||||
history.setFirstLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||
UserHistory history = UserHistory.EMPTY.withFirstLogin(
|
||||
ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||
User user1 = new User("1", "user1",
|
||||
new PasswordCrypt("blabla".getBytes(), "blabla".getBytes(), "PBKDF2WithHmacSHA512", 10000, 256), "Bob",
|
||||
"White", UserState.DISABLED, userRoles, Locale.ENGLISH, propertyMap, false, history);
|
||||
"White", UserState.DISABLED, groups, userRoles, Locale.ENGLISH, propertyMap, false, history);
|
||||
users.add(user1);
|
||||
|
||||
propertyMap = new HashMap<>();
|
||||
propertyMap.put("prop2", "value2");
|
||||
groups = new HashSet<>();
|
||||
groups.add("group2");
|
||||
userRoles = new HashSet<>();
|
||||
userRoles.add("role2");
|
||||
history = new UserHistory();
|
||||
history.setFirstLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||
history.setLastLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 5, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||
history = UserHistory.EMPTY.withFirstLogin(
|
||||
ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()))
|
||||
.withLastLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 5, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||
User user2 = new User("2", "user2", new PasswordCrypt("haha".getBytes(), "haha".getBytes(), null, -1, -1),
|
||||
"Leonard", "Sheldon", UserState.ENABLED, userRoles, Locale.ENGLISH, propertyMap, false, history);
|
||||
"Leonard", "Sheldon", UserState.ENABLED, groups, userRoles, Locale.ENGLISH, propertyMap, false,
|
||||
history);
|
||||
users.add(user2);
|
||||
|
||||
File modelFile = new File(TARGET_TEST + "PrivilegeUsersTest.xml");
|
||||
PrivilegeUsersDomWriter configSaxWriter = new PrivilegeUsersDomWriter(users, modelFile);
|
||||
PrivilegeUsersSaxWriter configSaxWriter = new PrivilegeUsersSaxWriter(users, modelFile);
|
||||
configSaxWriter.write();
|
||||
|
||||
PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader(true);
|
||||
|
@ -342,8 +427,8 @@ public class XmlTest {
|
|||
assertEquals(user1.getFirstname(), parsedUser1.getFirstname());
|
||||
assertEquals(user1.getLastname(), parsedUser1.getLastname());
|
||||
assertEquals(user1.getLocale(), parsedUser1.getLocale());
|
||||
assertArrayEquals(user1.getPasswordCrypt().getPassword(), parsedUser1.getPasswordCrypt().getPassword());
|
||||
assertArrayEquals(user1.getPasswordCrypt().getSalt(), parsedUser1.getPasswordCrypt().getSalt());
|
||||
assertArrayEquals(user1.getPasswordCrypt().password(), parsedUser1.getPasswordCrypt().password());
|
||||
assertArrayEquals(user1.getPasswordCrypt().salt(), parsedUser1.getPasswordCrypt().salt());
|
||||
assertEquals(user1.getProperties(), parsedUser1.getProperties());
|
||||
assertEquals(user1.getUserId(), parsedUser1.getUserId());
|
||||
assertEquals(user1.getUserState(), parsedUser1.getUserState());
|
||||
|
@ -352,8 +437,8 @@ public class XmlTest {
|
|||
assertEquals(user2.getFirstname(), parsedUser2.getFirstname());
|
||||
assertEquals(user2.getLastname(), parsedUser2.getLastname());
|
||||
assertEquals(user2.getLocale(), parsedUser2.getLocale());
|
||||
assertArrayEquals(user2.getPasswordCrypt().getPassword(), parsedUser2.getPasswordCrypt().getPassword());
|
||||
assertArrayEquals(user2.getPasswordCrypt().getSalt(), parsedUser2.getPasswordCrypt().getSalt());
|
||||
assertArrayEquals(user2.getPasswordCrypt().password(), parsedUser2.getPasswordCrypt().password());
|
||||
assertArrayEquals(user2.getPasswordCrypt().salt(), parsedUser2.getPasswordCrypt().salt());
|
||||
assertEquals(user2.getProperties(), parsedUser2.getProperties());
|
||||
assertEquals(user2.getUserId(), parsedUser2.getUserId());
|
||||
assertEquals(user2.getUserState(), parsedUser2.getUserState());
|
||||
|
@ -361,13 +446,48 @@ public class XmlTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void canWriteRoles() {
|
||||
public void canWriteGroups() throws XMLStreamException, IOException {
|
||||
|
||||
Map<String, IPrivilege> privilegeMap;
|
||||
Map<String, String> propertyMap;
|
||||
Set<String> roles;
|
||||
|
||||
List<Group> groups = new ArrayList<>();
|
||||
propertyMap = new HashMap<>();
|
||||
propertyMap.put("prop1", "value1");
|
||||
roles = new HashSet<>();
|
||||
roles.add("role1");
|
||||
Group newGroup = new Group("group1", roles, propertyMap);
|
||||
groups.add(newGroup);
|
||||
|
||||
File modelFile = new File(TARGET_TEST + "PrivilegeGroupsTest.xml");
|
||||
PrivilegeGroupsSaxWriter configSaxWriter = new PrivilegeGroupsSaxWriter(groups, modelFile);
|
||||
configSaxWriter.write();
|
||||
|
||||
PrivilegeGroupsSaxReader xmlHandler = new PrivilegeGroupsSaxReader();
|
||||
XmlHelper.parseDocument(modelFile, xmlHandler);
|
||||
|
||||
Map<String, Group> parsedGroups = xmlHandler.getGroups();
|
||||
assertNotNull(parsedGroups);
|
||||
assertEquals(1, parsedGroups.size());
|
||||
|
||||
// group group1
|
||||
Group parsedGroup1 = parsedGroups.get("group1");
|
||||
assertNotNull(parsedGroup1);
|
||||
assertEquals("group1", parsedGroup1.name());
|
||||
MatcherAssert.assertThat(parsedGroup1.roles(), containsInAnyOrder("role1"));
|
||||
Map<String, String> properties = parsedGroup1.getProperties();
|
||||
assertEquals(new HashSet<>(List.of("prop1")), properties.keySet());
|
||||
assertEquals("value1", properties.get("prop1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canWriteRoles() throws XMLStreamException, IOException {
|
||||
|
||||
Map<String, Privilege> privilegeMap;
|
||||
List<Role> roles = new ArrayList<>();
|
||||
Set<String> list = Collections.emptySet();
|
||||
privilegeMap = new HashMap<>();
|
||||
privilegeMap.put("priv1", new PrivilegeImpl("priv1", "DefaultPrivilege", true, list, list));
|
||||
privilegeMap.put("priv1", new Privilege("priv1", "DefaultPrivilege", true, list, list));
|
||||
Role role1 = new Role("role1", privilegeMap);
|
||||
roles.add(role1);
|
||||
|
||||
|
@ -376,13 +496,13 @@ public class XmlTest {
|
|||
denyList.add("myself");
|
||||
Set<String> allowList = new HashSet<>();
|
||||
allowList.add("other");
|
||||
privilegeMap.put("priv2", new PrivilegeImpl("priv2", "DefaultPrivilege", false, denyList, allowList));
|
||||
privilegeMap.put("priv2", new Privilege("priv2", "DefaultPrivilege", false, denyList, allowList));
|
||||
Role role2 = new Role("role2", privilegeMap);
|
||||
roles.add(role2);
|
||||
|
||||
File modelFile = new File(TARGET_TEST + "PrivilegeRolesTest.xml");
|
||||
PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, modelFile);
|
||||
configSaxWriter.write();
|
||||
PrivilegeRolesSaxWriter writer = new PrivilegeRolesSaxWriter(roles, modelFile);
|
||||
writer.write();
|
||||
|
||||
PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader();
|
||||
XmlHelper.parseDocument(modelFile, xmlHandler);
|
||||
|
@ -400,8 +520,8 @@ public class XmlTest {
|
|||
Set<String> privilegeNames = role1.getPrivilegeNames();
|
||||
assertEquals(privilegeNames, parsedRole1.getPrivilegeNames());
|
||||
for (String privilegeName : privilegeNames) {
|
||||
IPrivilege privilege = role1.getPrivilege(privilegeName);
|
||||
IPrivilege privilege2 = parsedRole1.getPrivilege(privilegeName);
|
||||
Privilege privilege = role1.getPrivilege(privilegeName);
|
||||
Privilege privilege2 = parsedRole1.getPrivilege(privilegeName);
|
||||
assertNotNull(privilege);
|
||||
assertNotNull(privilege2);
|
||||
|
||||
|
@ -415,8 +535,8 @@ public class XmlTest {
|
|||
assertEquals(role2.getPrivilegeNames(), parsedRole2.getPrivilegeNames());
|
||||
privilegeNames = role2.getPrivilegeNames();
|
||||
for (String privilegeName : privilegeNames) {
|
||||
IPrivilege privilege = role2.getPrivilege(privilegeName);
|
||||
IPrivilege privilege2 = parsedRole2.getPrivilege(privilegeName);
|
||||
Privilege privilege = role2.getPrivilege(privilegeName);
|
||||
Privilege privilege2 = parsedRole2.getPrivilege(privilegeName);
|
||||
assertNotNull(privilege);
|
||||
assertNotNull(privilege2);
|
||||
|
||||
|
|
|
@ -28,9 +28,10 @@ public class DummySsoHandler implements SingleSignOnHandler {
|
|||
|
||||
@SuppressWarnings("unchecked") Map<String, String> map = (Map<String, String>) data;
|
||||
|
||||
Set<String> groups = Arrays.stream(map.get("groups").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<>();
|
||||
return new User(map.get("userId"), map.get("username"), null, map.get("firstName"), map.get("lastName"),
|
||||
UserState.REMOTE, roles, Locale.ENGLISH, properties, false, new UserHistory());
|
||||
UserState.REMOTE, groups, roles, Locale.ENGLISH, properties, false, UserHistory.EMPTY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<Parameters>
|
||||
<Parameter name="basePath" value="target/${target}"/>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsersMerge.xml"/>
|
||||
<Parameter name="groupsXmlFile" value="PrivilegeGroupsMerge.xml"/>
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRolesMerge.xml"/>
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<Groups>
|
||||
<Group name="GroupA"/>
|
||||
<Group name="AppUserLocationA">
|
||||
<Roles>
|
||||
<Role>AppUser</Role>
|
||||
<Role>ModelAccessor</Role>
|
||||
<Role>UserPrivileges</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="location" value="LocationA"/>
|
||||
</Properties>
|
||||
</Group>
|
||||
</Groups>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<Groups>
|
||||
<Group name="GroupA1">
|
||||
<Roles>
|
||||
<Role>RoleA1</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="location" value="LocationA1"/>
|
||||
</Properties>
|
||||
</Group>
|
||||
<Group name="GroupA2">
|
||||
<Roles>
|
||||
<Role>RoleA2</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="location" value="LocationA2"/>
|
||||
</Properties>
|
||||
</Group>
|
||||
|
||||
<Group name="GroupB1">
|
||||
<Roles>
|
||||
<Role>RoleB1</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="location" value="LocationB1"/>
|
||||
</Properties>
|
||||
</Group>
|
||||
|
||||
<Group name="GroupB2">
|
||||
<Roles>
|
||||
<Role>RoleB2</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="location" value="LocationB2"/>
|
||||
</Properties>
|
||||
</Group>
|
||||
</Groups>
|
|
@ -2,61 +2,32 @@
|
|||
<Roles>
|
||||
|
||||
<Role name="PrivilegeAdmin">
|
||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserRolesService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveRoleFromUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeAddUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeAddRoleToUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeUpdateRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeRemoveRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeRemovePrivilegeFromRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeAddRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeAddOrReplacePrivilegeOnRoleService</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
|
||||
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="InvalidateSession" policy="UserSessionAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RequirePasswordChange" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
|
||||
<Allow>Reload</Allow>
|
||||
<Allow>GetCertificates</Allow>
|
||||
<Allow>GetPolicies</Allow>
|
||||
<Allow>Persist</Allow>
|
||||
<Allow>GetCertificates</Allow>
|
||||
<Allow>PersistSessions</Allow>
|
||||
<Allow>Reload</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
|
||||
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
|
||||
<Deny>SYSTEM</Deny>
|
||||
<Allow>DISABLED</Allow>
|
||||
<Allow>ENABLED</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeAddRoleToUser" policy="UserAccessPrivilege">
|
||||
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
|
||||
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
|
||||
|
@ -65,15 +36,35 @@
|
|||
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeRemoveRoleFromUser" policy="UserAccessPrivilege">
|
||||
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
|
||||
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
|
||||
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
|
||||
<Deny>SYSTEM</Deny>
|
||||
<Allow>DISABLED</Allow>
|
||||
<Allow>ENABLED</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="RequirePasswordChange" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeAddRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeRemoveRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.roles.PrivilegeUpdateRoleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeAddUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveUserService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserStateService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserRolesService</Allow>
|
||||
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserService</Allow>
|
||||
</Privilege>
|
||||
</Role>
|
||||
|
||||
<Role name="AppUser">
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
<Lastname>Administrator</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en-GB</Locale>
|
||||
<Groups>
|
||||
<Group>GroupA</Group>
|
||||
</Groups>
|
||||
<Roles>
|
||||
<Role>PrivilegeAdmin</Role>
|
||||
<Role>AppUser</Role>
|
||||
|
@ -21,9 +24,11 @@
|
|||
<Lastname>Administrator</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en-GB</Locale>
|
||||
<Groups>
|
||||
<Group>AppUserLocationA</Group>
|
||||
</Groups>
|
||||
<Roles>
|
||||
<Role>PrivilegeAdmin</Role>
|
||||
<Role>AppUser</Role>
|
||||
</Roles>
|
||||
<Properties>
|
||||
<Property name="organization" value="eitchnet.ch"/>
|
||||
|
|
|
@ -23,4 +23,26 @@
|
|||
</Roles>
|
||||
</User>
|
||||
|
||||
<User userId="3" username="userC" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
|
||||
<Firstname>System User</Firstname>
|
||||
<Lastname>Administrator</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en-GB</Locale>
|
||||
<Groups>
|
||||
<Group>GroupA1</Group>
|
||||
<Group>GroupA2</Group>
|
||||
</Groups>
|
||||
</User>
|
||||
|
||||
<User userId="4" username="userD" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
|
||||
<Firstname>System User</Firstname>
|
||||
<Lastname>Administrator</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en-GB</Locale>
|
||||
<Groups>
|
||||
<Group>GroupB1</Group>
|
||||
<Group>GroupB2</Group>
|
||||
</Groups>
|
||||
</User>
|
||||
|
||||
</Users>
|
|
@ -1,15 +1,5 @@
|
|||
package li.strolch.execution;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static li.strolch.model.StrolchModelConstants.*;
|
||||
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
|
||||
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfMaps;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.ObserverEvent;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
|
@ -28,6 +18,16 @@ import li.strolch.privilege.model.Certificate;
|
|||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.utils.collections.MapOfMaps;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static li.strolch.model.StrolchModelConstants.*;
|
||||
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
|
||||
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfMaps;
|
||||
|
||||
/**
|
||||
* The event based execution handler waits for events in that the {@link ExecutionPolicy} implementations must call the
|
||||
* relevant methods when the work is complete. Afterwards the next {@link Action} in the procedure is executed
|
||||
|
@ -51,12 +51,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
|
||||
@Override
|
||||
public boolean isControlling(Activity activity) {
|
||||
return this.controllers.containsElement(getDefaultRealm(), activity.getLocator());
|
||||
return this.controllers.containsElement(getDefaultRealm(), activity.getRootElement().getLocator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlling(String realm, Activity activity) {
|
||||
return this.controllers.containsElement(realm, activity.getLocator());
|
||||
return this.controllers.containsElement(realm, activity.getRootElement().getLocator());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,12 +83,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
|
||||
@Override
|
||||
public Controller getController(Activity activity) {
|
||||
return getController(getDefaultRealm(), activity.getLocator());
|
||||
return getController(getDefaultRealm(), activity.getRootElement().getLocator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Controller getController(String realm, Activity activity) {
|
||||
return this.controllers.getElement(realm, activity.getLocator());
|
||||
return this.controllers.getElement(realm, activity.getRootElement().getLocator());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,7 +157,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
synchronized (this.controllers) {
|
||||
Map<Locator, Controller> map = this.controllers.getMap(realm);
|
||||
if (map == null) {
|
||||
logger.error("No controllers for realm " + realm);
|
||||
logger.info("No controllers for realm " + realm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -171,26 +171,28 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addForExecution(Activity activity) {
|
||||
addForExecution(getDefaultRealm(), activity);
|
||||
public Controller addForExecution(Activity activity) {
|
||||
return addForExecution(getDefaultRealm(), activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addForExecution(String realm, Activity activity) {
|
||||
public Controller addForExecution(String realm, Activity activity) {
|
||||
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||
if (state == ExecutionHandlerState.HaltNew)
|
||||
throw new IllegalStateException(
|
||||
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
||||
|
||||
if (this.controllers.containsElement(realm, activity.getLocator()))
|
||||
throw new IllegalStateException(activity.getLocator() + " is already registered for execution!");
|
||||
Locator locator = activity.getRootElement().getLocator();
|
||||
if (this.controllers.containsElement(realm, locator))
|
||||
throw new IllegalStateException(locator + " is already registered for execution!");
|
||||
|
||||
logger.info("Added " + activity.getLocator() + " @ " + realm);
|
||||
logger.info("Added " + locator + " @ " + realm);
|
||||
Controller controller = newController(realm, activity);
|
||||
this.controllers.addElement(realm, activity.getLocator(), controller);
|
||||
this.controllers.addElement(realm, locator, controller);
|
||||
notifyObserverAdd(controller);
|
||||
|
||||
triggerExecution(realm);
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,10 +207,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
throw new IllegalStateException(
|
||||
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
||||
|
||||
Controller controller = this.controllers.getElement(realm, activity.getLocator());
|
||||
Locator locator = activity.getRootElement().getLocator();
|
||||
Controller controller = this.controllers.getElement(realm, locator);
|
||||
if (controller == null) {
|
||||
controller = newController(realm, activity);
|
||||
this.controllers.addElement(realm, activity.getLocator(), controller);
|
||||
this.controllers.addElement(realm, locator, controller);
|
||||
notifyObserverAdd(controller);
|
||||
}
|
||||
|
||||
|
@ -296,7 +299,8 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
if (activity.isReadOnly())
|
||||
activity = activity.getClone(true);
|
||||
|
||||
logger.info("Restarting Execution of " + activity.getLocator() + " on realm " + realmName);
|
||||
Locator locator = activity.getRootElement().getLocator();
|
||||
logger.info("Restarting Execution of " + locator + " on realm " + realmName);
|
||||
|
||||
// in execution actions need to be in state STOPPED to restart
|
||||
activity.findActionsDeep(a -> a.getState().inExecutionPhase()).forEach(a -> {
|
||||
|
@ -309,7 +313,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
|
||||
// register for execution
|
||||
Controller controller = newController(realmName, activity);
|
||||
this.controllers.addElement(realmName, activity.getLocator(), controller);
|
||||
this.controllers.addElement(realmName, locator, controller);
|
||||
});
|
||||
|
||||
// commit changes to state
|
||||
|
|
|
@ -219,7 +219,7 @@ public abstract class ExecutionHandler extends StrolchComponent {
|
|||
* @throws IllegalStateException
|
||||
* if the default realm is not set!
|
||||
*/
|
||||
public abstract void addForExecution(Activity activity);
|
||||
public abstract Controller addForExecution(Activity activity);
|
||||
|
||||
/**
|
||||
* Registers the given {@link Activity} for execution. Execution is started when the concrete implementation deems
|
||||
|
@ -230,7 +230,7 @@ public abstract class ExecutionHandler extends StrolchComponent {
|
|||
* @param activity
|
||||
* the {@link Activity}
|
||||
*/
|
||||
public abstract void addForExecution(String realm, Activity activity);
|
||||
public abstract Controller addForExecution(String realm, Activity activity);
|
||||
|
||||
/**
|
||||
* Registers the given {@link Activity} for execution on the default realm, and submits it for execution immediately
|
||||
|
|
|
@ -20,8 +20,12 @@ import li.strolch.privilege.model.PrivilegeContext;
|
|||
import li.strolch.runtime.StrolchConstants;
|
||||
import li.strolch.runtime.privilege.PrivilegedRunnable;
|
||||
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
|
||||
import li.strolch.utils.time.PeriodDuration;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -53,6 +57,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
protected Locator resourceLoc;
|
||||
protected Locator actionLoc;
|
||||
|
||||
protected List<ScheduledFuture<?>> futures;
|
||||
|
||||
/**
|
||||
* The TX for this execution policy. The TX needs to be updated when this execution policy has a longer life time
|
||||
* than the actual TX
|
||||
|
@ -63,6 +69,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
super(tx);
|
||||
this.tx = tx;
|
||||
this.realm = tx.getRealmName();
|
||||
this.futures = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,6 +232,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
public void stop() {
|
||||
this.stopped = true;
|
||||
try {
|
||||
this.futures.forEach(future -> future.cancel(false));
|
||||
handleStopped();
|
||||
} catch (Exception e) {
|
||||
logger.error("Stopping failed for " + this.actionLoc, e);
|
||||
|
@ -246,6 +254,9 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
* @param state the new state to set
|
||||
*/
|
||||
protected void setActionState(Action action, State state) {
|
||||
if (action.getState().inClosedPhase())
|
||||
throw new IllegalStateException("Action " + action.getLocator() + " has state " + action.getState() +
|
||||
" and can not be changed to " + state);
|
||||
|
||||
action.setState(state);
|
||||
|
||||
|
@ -270,6 +281,17 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
return action.findObjectivesParam(PARAM_DURATION, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays the given {@link Runnable} by the given {@link PeriodDuration}
|
||||
*
|
||||
* @param duration the duration to delay
|
||||
* @param runnable the action to delay
|
||||
*/
|
||||
public void delay(PeriodDuration duration, Runnable runnable) {
|
||||
long delayMs = duration.toMillis();
|
||||
this.futures.add(getDelayedExecutionTimer().delay(delayMs, runnable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays the given {@link Runnable} by the given {@link Duration}
|
||||
*
|
||||
|
@ -278,7 +300,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
*/
|
||||
public void delay(Duration duration, Runnable runnable) {
|
||||
long delayMs = duration.toMillis();
|
||||
getDelayedExecutionTimer().delay(delayMs, runnable);
|
||||
this.futures.add(getDelayedExecutionTimer().delay(delayMs, runnable));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -321,7 +343,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
|||
delayMs = 20;
|
||||
}
|
||||
logger.info("Delaying runnable " + runnable + " by " + formatMillisecondsDuration(delayMs));
|
||||
getDelayedExecutionTimer().delay(delayMs, runnable);
|
||||
this.futures.add(getDelayedExecutionTimer().delay(delayMs, runnable));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -92,7 +92,7 @@ public class SimpleExecution extends ExecutionPolicy {
|
|||
protected void toWarning(LogMessage message) {
|
||||
cancelWarningTask();
|
||||
addMessage(message);
|
||||
getExecutionHandler().toWarning(this.realm, message.getLocator());
|
||||
getExecutionHandler().toWarning(this.realm, this.actionLoc);
|
||||
}
|
||||
|
||||
protected void toExecuted() throws Exception {
|
||||
|
@ -126,7 +126,7 @@ public class SimpleExecution extends ExecutionPolicy {
|
|||
stop();
|
||||
logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage());
|
||||
addMessage(message);
|
||||
getExecutionHandler().toError(this.realm, message.getLocator());
|
||||
getExecutionHandler().toError(this.realm, this.actionLoc);
|
||||
}
|
||||
|
||||
protected void setActionStateWithValueChange(Action action, State execution, double value) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue