Merge branch 'develop' into release/2.1
This commit is contained in:
commit
42ee3de41f
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.policy;
|
package li.strolch.policy;
|
||||||
|
|
||||||
import static li.strolch.model.StrolchModelConstants.PolicyConstants.PARAM_ORDER;
|
|
||||||
|
|
||||||
import li.strolch.agent.api.ComponentContainer;
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
import li.strolch.agent.api.StrolchAgent;
|
import li.strolch.agent.api.StrolchAgent;
|
||||||
import li.strolch.agent.api.StrolchComponent;
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
|
@ -27,6 +25,8 @@ import li.strolch.service.api.Command;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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}
|
* Interface for all Strolch policies, which are instantiated by the {@link PolicyHandler}
|
||||||
*
|
*
|
||||||
|
@ -103,6 +103,14 @@ public abstract class StrolchPolicy {
|
||||||
return this.tx;
|
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) {
|
protected Order getOrder(IActivityElement element) {
|
||||||
return tx().getOrderByRelation(element.getRootElement(), PARAM_ORDER, true);
|
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 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;
|
||||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH;
|
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 static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -126,7 +126,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
||||||
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
|
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
|
||||||
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
|
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
|
||||||
File configPath = runtimeConfig.getConfigPath();
|
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);
|
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.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
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
|
* 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
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
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
|
* 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
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
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 {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
preValidate(privilege, restrictable);
|
preValidate(privilege, restrictable);
|
||||||
|
|
|
@ -13,21 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package li.strolch.rest;
|
package li.strolch.runtime.sessions;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
import li.strolch.agent.api.ComponentContainer;
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
import li.strolch.agent.api.StrolchComponent;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.SimpleRestrictable;
|
import li.strolch.privilege.model.SimpleRestrictable;
|
||||||
import li.strolch.privilege.model.Usage;
|
import li.strolch.privilege.model.Usage;
|
||||||
import li.strolch.rest.model.UserSession;
|
|
||||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
import li.strolch.utils.dbc.DBC;
|
import li.strolch.utils.dbc.DBC;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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>
|
* @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_TTL_MINUTES = "session.ttl.minutes";
|
||||||
public static final String PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES = "session.maxKeepAlive.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 static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
|
||||||
private PrivilegeHandler privilegeHandler;
|
private PrivilegeHandler privilegeHandler;
|
||||||
private final Map<String, Certificate> certificateMap;
|
private final Map<String, Certificate> certificateMap;
|
||||||
private boolean reloadSessions;
|
|
||||||
private int sessionTtlMinutes;
|
private int sessionTtlMinutes;
|
||||||
private int maxKeepAliveMinutes;
|
private int maxKeepAliveMinutes;
|
||||||
|
|
||||||
|
@ -74,6 +70,29 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
return this.sessionTtlMinutes;
|
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
|
@Override
|
||||||
public int getSessionMaxKeepAliveMinutes() {
|
public int getSessionMaxKeepAliveMinutes() {
|
||||||
return this.maxKeepAliveMinutes;
|
return this.maxKeepAliveMinutes;
|
||||||
|
@ -89,30 +108,14 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
this.sessionTtlMinutes = configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30);
|
this.sessionTtlMinutes = configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30);
|
||||||
this.maxKeepAliveMinutes = configuration.getInt(PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES,
|
this.maxKeepAliveMinutes = configuration.getInt(PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES,
|
||||||
Math.max(this.sessionTtlMinutes, 30));
|
Math.max(this.sessionTtlMinutes, 30));
|
||||||
this.reloadSessions = configuration.getBoolean(PARAM_SESSION_RELOAD_SESSIONS, false);
|
|
||||||
super.initialize(configuration);
|
super.initialize(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
||||||
this.certificateMap.clear();
|
|
||||||
|
|
||||||
if (this.reloadSessions) {
|
refreshSessions();
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.validateSessionsTask = getScheduledExecutor("SessionHandler").scheduleWithFixedDelay(
|
this.validateSessionsTask = getScheduledExecutor("SessionHandler").scheduleWithFixedDelay(
|
||||||
this::checkSessionsForTimeout, 5, 1, TimeUnit.MINUTES);
|
this::checkSessionsForTimeout, 5, 1, TimeUnit.MINUTES);
|
||||||
|
@ -126,27 +129,6 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
if (this.validateSessionsTask != null)
|
if (this.validateSessionsTask != null)
|
||||||
this.validateSessionsTask.cancel(true);
|
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;
|
this.privilegeHandler = null;
|
||||||
super.stop();
|
super.stop();
|
||||||
}
|
}
|
||||||
|
@ -321,8 +303,8 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSessionsForTimeout() {
|
private void checkSessionsForTimeout() {
|
||||||
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minus(this.maxKeepAliveMinutes, ChronoUnit.MINUTES);
|
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minusMinutes(this.maxKeepAliveMinutes);
|
||||||
ZonedDateTime timeOutTime = ZonedDateTime.now().minus(this.sessionTtlMinutes, ChronoUnit.MINUTES);
|
ZonedDateTime timeOutTime = ZonedDateTime.now().minusMinutes(this.sessionTtlMinutes);
|
||||||
|
|
||||||
Map<String, Certificate> certificateMap = getCertificateMapCopy();
|
Map<String, Certificate> certificateMap = getCertificateMapCopy();
|
||||||
for (Certificate certificate : certificateMap.values()) {
|
for (Certificate certificate : certificateMap.values()) {
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package li.strolch.rest;
|
package li.strolch.runtime.sessions;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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.Certificate;
|
||||||
import li.strolch.privilege.model.PrivilegeContext;
|
import li.strolch.privilege.model.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Usage;
|
import li.strolch.privilege.model.Usage;
|
||||||
import li.strolch.rest.model.UserSession;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link StrolchSessionHandler} implements session management. It authenticates, validates and invalidates session
|
* 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 {
|
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
|
* Returns the time to live for a session in minutes
|
||||||
*
|
*
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package li.strolch.rest.model;
|
package li.strolch.runtime.sessions;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</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() {
|
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
|
// execution
|
||||||
if (states.contains(EXECUTABLE) || states.contains(EXECUTION))
|
if (states.contains(EXECUTABLE) || states.contains(EXECUTION))
|
||||||
return EXECUTION;
|
return EXECUTION;
|
||||||
if (states.contains(EXECUTED) && (states.contains(CREATED) || states.contains(PLANNING) || states.contains(
|
if (states.contains(EXECUTED) &&
|
||||||
PLANNED)))
|
(states.contains(CREATED) || states.contains(PLANNING) || states.contains(PLANNED)))
|
||||||
return EXECUTION;
|
return EXECUTION;
|
||||||
|
|
||||||
// executed
|
// executed
|
||||||
|
|
|
@ -740,6 +740,8 @@ public class Activity extends AbstractStrolchRootElement
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity ensureModifiable() {
|
public Activity ensureModifiable() {
|
||||||
|
if (!this.isRootElement())
|
||||||
|
throw new IllegalStateException("Only call this method on the root element!");
|
||||||
if (isReadOnly())
|
if (isReadOnly())
|
||||||
return getClone(true);
|
return getClone(true);
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package li.strolch.model.json;
|
package li.strolch.model.json;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
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.UserRep;
|
||||||
import li.strolch.privilege.model.UserState;
|
import li.strolch.privilege.model.UserState;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
public class PrivilegeElementFromJsonVisitor {
|
public class PrivilegeElementFromJsonVisitor {
|
||||||
|
|
||||||
public UserRep userRepFromJson(String string) {
|
public UserRep userRepFromJson(String string) {
|
||||||
|
@ -32,11 +32,12 @@ public class PrivilegeElementFromJsonVisitor {
|
||||||
|
|
||||||
String name = nameE == null ? null : nameE.getAsString().trim();
|
String name = nameE == null ? null : nameE.getAsString().trim();
|
||||||
|
|
||||||
List<PrivilegeRep> privileges = new ArrayList<>();
|
Map<String, PrivilegeRep> privileges = new HashMap<>();
|
||||||
if (privilegesE != null) {
|
if (privilegesE != null) {
|
||||||
JsonArray privilegesArr = privilegesE.getAsJsonArray();
|
JsonArray privilegesArr = privilegesE.getAsJsonArray();
|
||||||
for (JsonElement privilegeE : privilegesArr) {
|
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 lastNameE = jsonObject.get("lastname");
|
||||||
JsonElement userStateE = jsonObject.get("userState");
|
JsonElement userStateE = jsonObject.get("userState");
|
||||||
JsonElement localeE = jsonObject.get("locale");
|
JsonElement localeE = jsonObject.get("locale");
|
||||||
|
JsonElement groupsE = jsonObject.get("groups");
|
||||||
JsonElement rolesE = jsonObject.get("roles");
|
JsonElement rolesE = jsonObject.get("roles");
|
||||||
JsonElement propertiesE = jsonObject.get("properties");
|
JsonElement propertiesE = jsonObject.get("properties");
|
||||||
|
|
||||||
|
@ -90,16 +92,11 @@ public class PrivilegeElementFromJsonVisitor {
|
||||||
String firstname = firstNameE == null ? null : firstNameE.getAsString().trim();
|
String firstname = firstNameE == null ? null : firstNameE.getAsString().trim();
|
||||||
String lastname = lastNameE == null ? null : lastNameE.getAsString().trim();
|
String lastname = lastNameE == null ? null : lastNameE.getAsString().trim();
|
||||||
UserState userState = userStateE == null ? null : UserState.valueOf(userStateE.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;
|
Set<String> groups = jsonArrayToSet(groupsE);
|
||||||
if (rolesE != null) {
|
|
||||||
roles = new HashSet<>();
|
Set<String> roles = jsonArrayToSet(rolesE);
|
||||||
JsonArray rolesArr = rolesE.getAsJsonArray();
|
|
||||||
for (JsonElement role : rolesArr) {
|
|
||||||
roles.add(role.getAsString().trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> properties = null;
|
Map<String, String> properties = null;
|
||||||
if (propertiesE != 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());
|
jsonObject.addProperty("name", roleRep.getName());
|
||||||
|
|
||||||
JsonArray privilegesJ = new JsonArray();
|
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);
|
jsonObject.add("privileges", privilegesJ);
|
||||||
|
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
|
|
|
@ -1,46 +1,26 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege"/>
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/>
|
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/>
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -1,40 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Privilege>
|
<Privilege>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- parameters for the container itself -->
|
<Parameter name="secretKey" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
|
<Parameter name="secretSalt" value="CHANGE-ME"/>
|
||||||
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
|
|
||||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
|
||||||
</Parameters>
|
</Parameters>
|
||||||
|
|
||||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||||
<Parameters>
|
<Parameters>
|
||||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
|
||||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
|
||||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||||
<!-- default iterations: 200000 -->
|
|
||||||
<Parameter name="hashIterations" value="10000" />
|
<Parameter name="hashIterations" value="10000" />
|
||||||
<!-- default key length: 256 -->
|
|
||||||
<Parameter name="hashKeyLength" value="256" />
|
<Parameter name="hashKeyLength" value="256" />
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</EncryptionHandler>
|
</EncryptionHandler>
|
||||||
|
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
|
||||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
|
||||||
<Parameters>
|
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
|
||||||
</Parameters>
|
|
||||||
</PersistenceHandler>
|
|
||||||
|
|
||||||
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
|
|
||||||
</UserChallengeHandler>
|
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||||
|
@ -42,5 +23,4 @@
|
||||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
|
|
||||||
</Privilege>
|
</Privilege>
|
|
@ -14,6 +14,7 @@ public class PrivilegeConstants {
|
||||||
public static final String PRIMARY_LOCATION = "primaryLocation";
|
public static final String PRIMARY_LOCATION = "primaryLocation";
|
||||||
public static final String SECONDARY_LOCATIONS = "secondaryLocations";
|
public static final String SECONDARY_LOCATIONS = "secondaryLocations";
|
||||||
public static final String ROLES = "roles";
|
public static final String ROLES = "roles";
|
||||||
|
public static final String GROUPS = "groups";
|
||||||
public static final String EMAIL = "email";
|
public static final String EMAIL = "email";
|
||||||
|
|
||||||
public static final String ROLE_STROLCH_ADMIN = "StrolchAdmin";
|
public static final String ROLE_STROLCH_ADMIN = "StrolchAdmin";
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
package li.strolch.privilege.handler;
|
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.Context;
|
||||||
import javax.naming.NamingEnumeration;
|
import javax.naming.NamingEnumeration;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.PartialResultException;
|
||||||
import javax.naming.directory.*;
|
import javax.naming.directory.*;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -10,21 +20,20 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import li.strolch.privilege.base.AccessDeniedException;
|
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
||||||
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;
|
|
||||||
|
|
||||||
public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
|
|
||||||
protected static final Logger logger = LoggerFactory.getLogger(BaseLdapPrivilegeHandler.class);
|
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 providerUrl;
|
||||||
private String searchBase;
|
private String searchBase;
|
||||||
|
private String additionalFilter;
|
||||||
private String domain;
|
private String domain;
|
||||||
|
private String domainPrefix;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(ScheduledExecutorService executorService, Map<String, String> parameterMap,
|
public void initialize(ScheduledExecutorService executorService, Map<String, String> parameterMap,
|
||||||
|
@ -36,9 +45,24 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
userChallengeHandler, ssoHandler, policyMap);
|
userChallengeHandler, ssoHandler, policyMap);
|
||||||
|
|
||||||
this.providerUrl = parameterMap.get("providerUrl");
|
this.providerUrl = parameterMap.get("providerUrl");
|
||||||
|
logger.info("providerUrl: " + this.providerUrl);
|
||||||
this.searchBase = parameterMap.get("searchBase");
|
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
|
@Override
|
||||||
|
@ -49,52 +73,24 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
if (internalUser != null && internalUser.getUserState() != UserState.REMOTE)
|
if (internalUser != null && internalUser.getUserState() != UserState.REMOTE)
|
||||||
return super.checkCredentialsAndUserState(username, password);
|
return super.checkCredentialsAndUserState(username, password);
|
||||||
|
|
||||||
// Set up the environment for creating the initial context
|
String userPrincipalName;
|
||||||
Hashtable<String, String> env = new Hashtable<>();
|
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");
|
logger.info("User {} tries to login on ldap {}", username, this.providerUrl);
|
||||||
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);
|
|
||||||
|
|
||||||
// Create the initial context
|
// Create the initial context
|
||||||
DirContext ctx = null;
|
DirContext ctx = null;
|
||||||
try {
|
try {
|
||||||
ctx = new InitialDirContext(env);
|
ctx = new InitialDirContext(buildLdapEnv(password, userPrincipalName));
|
||||||
|
SearchResult searchResult = searchLdap(username, ctx, userPrincipalName);
|
||||||
//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");
|
|
||||||
|
|
||||||
User user = buildUserFromSearchResult(username, searchResult);
|
User user = buildUserFromSearchResult(username, searchResult);
|
||||||
|
|
||||||
// persist this user
|
// persist this user
|
||||||
|
@ -104,13 +100,15 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
this.persistenceHandler.replaceUser(user);
|
this.persistenceHandler.replaceUser(user);
|
||||||
|
|
||||||
if (this.autoPersistOnUserChangesData)
|
if (this.autoPersistOnUserChangesData)
|
||||||
this.persistenceHandler.persist();
|
persistModelAsync();
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
|
||||||
|
} catch (AccessDeniedException e) {
|
||||||
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("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 + this.domain + " on Ldap", e);
|
throw new AccessDeniedException("Could not login with user: " + username + " on Ldap", e);
|
||||||
} finally {
|
} finally {
|
||||||
if (ctx != null) {
|
if (ctx != null) {
|
||||||
try {
|
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 {
|
protected User buildUserFromSearchResult(String username, SearchResult sr) throws Exception {
|
||||||
Attributes attrs = sr.getAttributes();
|
Attributes attrs = sr.getAttributes();
|
||||||
|
|
||||||
|
@ -135,19 +192,20 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
Set<String> ldapGroups = getLdapGroups(username, attrs);
|
Set<String> ldapGroups = getLdapGroups(username, attrs);
|
||||||
logger.info("User " + username + " is member of the following LDAP groups: ");
|
logger.info("User " + username + " is member of the following LDAP groups: ");
|
||||||
ldapGroups.forEach(s -> logger.info("- " + s));
|
ldapGroups.forEach(s -> logger.info("- " + s));
|
||||||
|
Set<String> strolchGroups = mapToStrolchGroups(username, ldapGroups);
|
||||||
Set<String> strolchRoles = mapToStrolchRoles(username, ldapGroups);
|
Set<String> strolchRoles = mapToStrolchRoles(username, ldapGroups);
|
||||||
|
|
||||||
Map<String, String> properties = buildProperties(username, attrs, ldapGroups, strolchRoles);
|
Map<String, String> properties = buildProperties(username, attrs, ldapGroups, strolchRoles);
|
||||||
|
|
||||||
return new User(username, username, null, firstName, lastName, UserState.REMOTE, strolchRoles, locale,
|
return new User(username, username, null, firstName, lastName, UserState.REMOTE, strolchGroups, strolchRoles,
|
||||||
properties, false, new UserHistory());
|
locale, properties, false, UserHistory.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Map<String, String> buildProperties(String username, Attributes attrs, Set<String> ldapGroups,
|
protected abstract Map<String, String> buildProperties(String username, Attributes attrs, Set<String> ldapGroups,
|
||||||
Set<String> strolchRoles) throws Exception;
|
Set<String> strolchRoles) throws Exception;
|
||||||
|
|
||||||
protected String validateLdapUsername(String username, Attributes attrs) throws NamingException {
|
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()))
|
if (sAMAccountName == null || !username.equalsIgnoreCase(sAMAccountName.get().toString()))
|
||||||
throw new AccessDeniedException(
|
throw new AccessDeniedException(
|
||||||
"Could not login with user: " + username + this.domain + " on Ldap: Wrong LDAP Data");
|
"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> 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);
|
protected abstract Set<String> mapToStrolchRoles(String username, Set<String> ldapGroups);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ public class BasicPasswordStrengthHandler implements PasswordStrengthHandler {
|
||||||
String description;
|
String description;
|
||||||
|
|
||||||
if (this.maxLength < 100)
|
if (this.maxLength < 100)
|
||||||
description = MessageFormat
|
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthBetween"), this.minLength,
|
||||||
.format(getString(locale, "Privilege.passwordLengthBetween"), this.minLength, this.maxLength);
|
this.maxLength);
|
||||||
else
|
else
|
||||||
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthAtLeast"), this.minLength);
|
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthAtLeast"), this.minLength);
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ import static li.strolch.privilege.helper.XmlConstants.*;
|
||||||
* <p>
|
* <p>
|
||||||
* Required parameters:
|
* Required parameters:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link XmlConstants#XML_PARAM_HASH_ALGORITHM}</li>
|
* <li>{@link XmlConstants#PARAM_HASH_ALGORITHM}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -121,7 +121,7 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
MessageDigest digest = MessageDigest.getInstance(this.nonSaltAlgorithm);
|
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) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new PrivilegeException(MessageFormat.format("Algorithm {0} was not found!", nonSaltAlgorithm),
|
throw new PrivilegeException(MessageFormat.format("Algorithm {0} was not found!", nonSaltAlgorithm),
|
||||||
|
@ -151,9 +151,8 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPasswordCryptOutdated(PasswordCrypt passwordCrypt) {
|
public boolean isPasswordCryptOutdated(PasswordCrypt passwordCrypt) {
|
||||||
return passwordCrypt.getSalt() == null || passwordCrypt.getHashAlgorithm() == null ||
|
return passwordCrypt.salt() == null || passwordCrypt.hashAlgorithm() == null ||
|
||||||
passwordCrypt.getHashIterations() != this.iterations ||
|
passwordCrypt.hashIterations() != this.iterations || passwordCrypt.hashKeyLength() != this.keyLength;
|
||||||
passwordCrypt.getHashKeyLength() != this.keyLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,13 +162,13 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
||||||
this.secureRandom = new SecureRandom();
|
this.secureRandom = new SecureRandom();
|
||||||
|
|
||||||
// get hash algorithm parameters
|
// get hash algorithm parameters
|
||||||
this.algorithm = parameterMap.getOrDefault(XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
this.algorithm = parameterMap.getOrDefault(PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||||
this.nonSaltAlgorithm = parameterMap.getOrDefault(XML_PARAM_HASH_ALGORITHM_NON_SALT,
|
this.nonSaltAlgorithm = parameterMap.getOrDefault(PARAM_HASH_ALGORITHM_NON_SALT,
|
||||||
DEFAULT_ALGORITHM_NON_SALT);
|
DEFAULT_ALGORITHM_NON_SALT);
|
||||||
this.iterations = Integer.parseInt(
|
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(
|
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
|
// test non-salt hash algorithm
|
||||||
try {
|
try {
|
||||||
|
@ -178,7 +177,7 @@ public class DefaultEncryptionHandler implements EncryptionHandler {
|
||||||
MessageFormat.format("Using non-salt hashing algorithm {0}", this.nonSaltAlgorithm));
|
MessageFormat.format("Using non-salt hashing algorithm {0}", this.nonSaltAlgorithm));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}";
|
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());
|
e.getLocalizedMessage());
|
||||||
throw new PrivilegeException(msg, e);
|
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));
|
DefaultEncryptionHandler.logger.info(MessageFormat.format("Using hashing algorithm {0}", this.algorithm));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}";
|
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());
|
e.getLocalizedMessage());
|
||||||
throw new PrivilegeException(msg, e);
|
throw new PrivilegeException(msg, e);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,11 @@
|
||||||
package li.strolch.privilege.handler;
|
package li.strolch.privilege.handler;
|
||||||
|
|
||||||
import static java.lang.String.join;
|
import com.google.gson.JsonElement;
|
||||||
import static java.util.stream.Collectors.toSet;
|
import com.google.gson.JsonObject;
|
||||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
import com.google.gson.JsonParser;
|
||||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
import li.strolch.privilege.helper.LdapHelper;
|
||||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||||
|
import li.strolch.utils.dbc.DBC;
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.naming.directory.Attributes;
|
import javax.naming.directory.Attributes;
|
||||||
|
@ -13,12 +14,11 @@ import java.io.FileReader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import static java.lang.String.join;
|
||||||
import com.google.gson.JsonObject;
|
import static java.util.stream.Collectors.toSet;
|
||||||
import com.google.gson.JsonParser;
|
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||||
import li.strolch.privilege.helper.LdapHelper;
|
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||||
import li.strolch.utils.dbc.DBC;
|
|
||||||
|
|
||||||
public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
|
|
||||||
|
@ -42,15 +42,14 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
DBC.PRE.assertNotEmpty("realm must be set!", realm);
|
DBC.PRE.assertNotEmpty("realm must be set!", realm);
|
||||||
|
|
||||||
this.defaultLocale = parameterMap.containsKey("defaultLocale") ?
|
this.defaultLocale = parameterMap.containsKey("defaultLocale") ?
|
||||||
Locale.forLanguageTag(parameterMap.get("defaultLocale")) :
|
Locale.forLanguageTag(parameterMap.get("defaultLocale")) : Locale.getDefault();
|
||||||
Locale.getDefault();
|
|
||||||
|
|
||||||
String configFileS = parameterMap.get("configFile");
|
String configFileS = parameterMap.get("configFile");
|
||||||
DBC.PRE.assertNotEmpty("configFile param must be set!", configFileS);
|
DBC.PRE.assertNotEmpty("configFile param must be set!", configFileS);
|
||||||
File configFile = new File(configFileS);
|
File configFile = new File(configFileS);
|
||||||
if (!configFile.exists() || !configFile.isFile() || !configFile.canRead())
|
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 "
|
throw new IllegalStateException("configFile does not exist, is not a file, or can not be read at path " +
|
||||||
+ configFile.getAbsolutePath());
|
configFile.getAbsolutePath());
|
||||||
|
|
||||||
// parse the configuration file
|
// parse the configuration file
|
||||||
JsonObject configJ;
|
JsonObject configJ;
|
||||||
|
@ -82,14 +81,14 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
// validate the configuration
|
// validate the configuration
|
||||||
for (String name : this.ldapGroupNames) {
|
for (String name : this.ldapGroupNames) {
|
||||||
JsonObject config = ldapGroupConfigs.get(name).getAsJsonObject();
|
JsonObject config = ldapGroupConfigs.get(name).getAsJsonObject();
|
||||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray()
|
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray() ||
|
||||||
|| config.get(LOCATION).getAsJsonArray().size() == 0)
|
config.get(LOCATION).getAsJsonArray().isEmpty())
|
||||||
throw new IllegalStateException("LDAP Group " + name
|
throw new IllegalStateException("LDAP Group " + name +
|
||||||
+ " is missing a location attribute, or it is not an array or the array is empty");
|
" is missing a location attribute, or it is not an array or the array is empty");
|
||||||
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray()
|
if (!config.has(LOCATION) || !config.get(LOCATION).isJsonArray() ||
|
||||||
|| config.get(LOCATION).getAsJsonArray().size() == 0)
|
config.get(LOCATION).getAsJsonArray().isEmpty())
|
||||||
throw new IllegalStateException("LDAP Group " + name
|
throw new IllegalStateException("LDAP Group " + name +
|
||||||
+ " is missing a roles attribute, or it is not an array or the array is empty");
|
" is missing a roles attribute, or it is not an array or the array is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userLdapGroupOverrides = new HashMap<>();
|
this.userLdapGroupOverrides = new HashMap<>();
|
||||||
|
@ -133,33 +132,40 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
logger.info("Overriding LDAP group for user " + username + " to " + overrideGroup);
|
logger.info("Overriding LDAP group for user " + username + " to " + overrideGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> relevantLdapGroups = ldapGroups.stream()
|
Set<String> relevantLdapGroups = ldapGroups.stream().filter(s -> this.ldapGroupNames.contains(s))
|
||||||
.filter(s -> this.ldapGroupNames.contains(s))
|
|
||||||
.collect(toSet());
|
.collect(toSet());
|
||||||
if (relevantLdapGroups.isEmpty())
|
if (relevantLdapGroups.isEmpty())
|
||||||
throw new IllegalStateException("User " + username
|
throw new IllegalStateException("User " + username +
|
||||||
+ " can not login, as none of their LDAP Groups have mappings to Strolch Roles!");
|
" can not login, as none of their LDAP Groups have mappings to Strolch Roles!");
|
||||||
|
|
||||||
if (relevantLdapGroups.size() > 1) {
|
if (relevantLdapGroups.size() > 1) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"User " + username + " has multiple relevant LDAP Groups which will lead to undefined behaviour: "
|
"User " + username + " has multiple relevant LDAP Groups which will lead to undefined behaviour: " +
|
||||||
+ join(",", relevantLdapGroups));
|
join(",", relevantLdapGroups));
|
||||||
}
|
}
|
||||||
|
|
||||||
return relevantLdapGroups;
|
return relevantLdapGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> mapToStrolchGroups(String username, Set<String> ldapGroups) {
|
||||||
|
return mapLdapGroupToStrolch(ldapGroups, GROUPS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Set<String> mapToStrolchRoles(String username, Set<String> ldapGroups) {
|
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) {
|
for (String relevantLdapGroup : ldapGroups) {
|
||||||
JsonObject mappingJ = this.ldapGroupConfigs.get(relevantLdapGroup).getAsJsonObject();
|
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
|
@Override
|
||||||
|
@ -194,9 +200,8 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
} else {
|
} else {
|
||||||
String location = primaryLocationJ.getAsString();
|
String location = primaryLocationJ.getAsString();
|
||||||
if (!secondaryLocations.contains(location)) {
|
if (!secondaryLocations.contains(location)) {
|
||||||
logger.warn(
|
logger.warn("Primary location already set by previous LDAP Group config for LDAP Group " +
|
||||||
"Primary location already set by previous LDAP Group config for LDAP Group " + ldapGroup
|
ldapGroup + ", adding to secondary locations.");
|
||||||
+ ", adding to secondary locations.");
|
|
||||||
secondaryLocations.add(location);
|
secondaryLocations.add(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,9 +215,8 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
|
||||||
else
|
else
|
||||||
secondaryLocationsJ.getAsJsonArray().forEach(s -> secondaryLocations.add(s.getAsString()));
|
secondaryLocationsJ.getAsJsonArray().forEach(s -> secondaryLocations.add(s.getAsString()));
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn("Secondary locations already set by previous LDAP Group config for LDAP Group " +
|
||||||
"Secondary locations already set by previous LDAP Group config for LDAP Group " + ldapGroup
|
ldapGroup + ", adding additional");
|
||||||
+ ", adding additional");
|
|
||||||
if (secondaryLocationsJ.isJsonPrimitive())
|
if (secondaryLocationsJ.isJsonPrimitive())
|
||||||
secondaryLocations.add(secondaryLocationsJ.getAsString());
|
secondaryLocations.add(secondaryLocationsJ.getAsString());
|
||||||
else
|
else
|
||||||
|
|
|
@ -16,9 +16,9 @@ public class MailUserChallengeHandler extends UserChallengeHandler {
|
||||||
|
|
||||||
String subject = "Mail TAN";
|
String subject = "Mail TAN";
|
||||||
|
|
||||||
String text = "Hello " + user.getFirstname() + " " + user.getLastname() + "\n\n"
|
String text = "Hello " + user.getFirstname() + " " + user.getLastname() + "\n\n" +
|
||||||
+ "You have requested an action which requires you to respond to a challenge.\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;
|
"Please use the following code to response to the challenge:\n\n" + challenge;
|
||||||
String recipient = user.getEmail();
|
String recipient = user.getEmail();
|
||||||
if (StringHelper.isEmpty(recipient)) {
|
if (StringHelper.isEmpty(recipient)) {
|
||||||
String msg = "User {0} has no property {1}, so can not initiate challenge!";
|
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
|
* Initialize the concrete {@link PasswordStrengthHandler}. The passed parameter map contains any configuration the
|
||||||
* concrete {@link PasswordStrengthHandler} might need
|
* concrete {@link PasswordStrengthHandler} might need
|
||||||
*
|
*
|
||||||
* @param parameterMap
|
* @param parameterMap a map containing configuration properties
|
||||||
* a map containing configuration properties
|
|
||||||
*/
|
*/
|
||||||
void initialize(Map<String, String> parameterMap);
|
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
|
* Returns a description what a password must contain in order to be regarded as strong for this concrete
|
||||||
* implementation
|
* implementation
|
||||||
*
|
*
|
||||||
|
* @param locale the locale in which to return the description
|
||||||
|
*
|
||||||
* @return a description of a strong password
|
* @return a description of a strong password
|
||||||
* @param locale
|
|
||||||
*/
|
*/
|
||||||
String getDescription(Locale locale);
|
String getDescription(Locale locale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the validation of the given password
|
* Performs the validation of the given password
|
||||||
*
|
*
|
||||||
* @param password
|
* @param password the password to validate
|
||||||
* the password to validate
|
|
||||||
*
|
*
|
||||||
* @return true if the password meets the criteria for a strong password
|
* @return true if the password meets the criteria for a strong password
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,15 +15,18 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.handler;
|
package li.strolch.privilege.handler;
|
||||||
|
|
||||||
import java.util.List;
|
import li.strolch.privilege.model.Privilege;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import li.strolch.privilege.model.IPrivilege;
|
|
||||||
import li.strolch.privilege.model.Restrictable;
|
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.Role;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
import li.strolch.privilege.policy.PrivilegePolicy;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* The {@link PersistenceHandler} takes care of retrieving and persisting model objects to the underlying database. This
|
* 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>
|
* <p>
|
||||||
* The {@link PersistenceHandler} also serves the special {@link PrivilegePolicy} objects. These policies are special
|
* 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}
|
* 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>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -47,6 +50,13 @@ public interface PersistenceHandler {
|
||||||
*/
|
*/
|
||||||
List<User> getAllUsers();
|
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
|
* Returns all currently known {@link Role}s
|
||||||
*
|
*
|
||||||
|
@ -57,18 +67,25 @@ public interface PersistenceHandler {
|
||||||
/**
|
/**
|
||||||
* Returns a {@link User} object from the underlying database
|
* Returns a {@link User} object from the underlying database
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the name/id of the {@link User} object to return
|
||||||
* the name/id of the {@link User} object to return
|
|
||||||
*
|
*
|
||||||
* @return the {@link User} object, or null if it was not found
|
* @return the {@link User} object, or null if it was not found
|
||||||
*/
|
*/
|
||||||
User getUser(String username);
|
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
|
* Returns a {@link Role} object from the underlying database
|
||||||
*
|
*
|
||||||
* @param roleName
|
* @param roleName the name/id of the {@link Role} object to return
|
||||||
* the name/id of the {@link Role} object to return
|
|
||||||
*
|
*
|
||||||
* @return the {@link Role} object, or null if it was not found
|
* @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
|
* Removes a {@link User} with the given name and returns the removed object if it existed
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the name of the {@link User} to remove
|
||||||
* the name of the {@link User} to remove
|
|
||||||
*
|
*
|
||||||
* @return the {@link User} removed, or null if it did not exist
|
* @return the {@link User} removed, or null if it did not exist
|
||||||
*/
|
*/
|
||||||
User removeUser(String username);
|
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
|
* Removes a {@link Role} with the given name and returns the removed object if it existed
|
||||||
*
|
*
|
||||||
* @param roleName
|
* @param roleName the name of the {@link Role} to remove
|
||||||
* the name of the {@link Role} to remove
|
|
||||||
*
|
*
|
||||||
* @return the {@link Role} removed, or null if it did not exist
|
* @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
|
* Adds a {@link User} object to the underlying database
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user the {@link User} object to add
|
||||||
* the {@link User} object to add
|
|
||||||
*/
|
*/
|
||||||
void addUser(User user);
|
void addUser(User user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces the existing {@link User} object in the underlying database
|
* Replaces the existing {@link User} object in the underlying database
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user the {@link User} object to add
|
||||||
* the {@link User} object to add
|
|
||||||
*/
|
*/
|
||||||
void replaceUser(User user);
|
void replaceUser(User user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a {@link Role} object to the underlying database
|
* Adds a {@link Role} object to the underlying database
|
||||||
*
|
*
|
||||||
* @param role
|
* @param role the {@link Role} object to add
|
||||||
* the {@link User} object to add
|
|
||||||
*/
|
*/
|
||||||
void addRole(Role role);
|
void addRole(Role role);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces the {@link Role} object in the underlying database
|
* Replaces the {@link Role} object in the underlying database
|
||||||
*
|
*
|
||||||
* @param role
|
* @param role the {@link User} object to add
|
||||||
* the {@link User} object to add
|
|
||||||
*/
|
*/
|
||||||
void replaceRole(Role role);
|
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
|
* 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
|
* @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
|
* 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
|
* Initialize the concrete {@link PersistenceHandler}. The passed parameter map contains any configuration the
|
||||||
* concrete {@link PersistenceHandler} might need
|
* concrete {@link PersistenceHandler} might need
|
||||||
*
|
*
|
||||||
* @param parameterMap
|
* @param parameterMap a map containing configuration properties
|
||||||
* a map containing configuration properties
|
|
||||||
*/
|
*/
|
||||||
void initialize(Map<String, String> parameterMap);
|
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;
|
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.base.*;
|
||||||
import li.strolch.privilege.model.*;
|
import li.strolch.privilege.model.*;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
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
|
* 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
|
* 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
|
* Returns a {@link UserRep} for the given username
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 username
|
|
||||||
* the name of the {@link UserRep} to return
|
|
||||||
*
|
*
|
||||||
* @return the {@link UserRep} for the given username, or null if it was not found
|
* @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
|
* Returns a {@link RoleRep} for the given roleName
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 roleName
|
|
||||||
* the name of the {@link RoleRep} to return
|
|
||||||
*
|
*
|
||||||
* @return the {@link RoleRep} for the given roleName, or null if it was not found
|
* @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
|
* Returns the map of {@link PrivilegePolicy} definitions
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
|
||||||
*
|
*
|
||||||
* @return the map of {@link PrivilegePolicy} definitions
|
* @return the map of {@link PrivilegePolicy} definitions
|
||||||
*/
|
*/
|
||||||
|
@ -246,8 +241,7 @@ public interface PrivilegeHandler {
|
||||||
/**
|
/**
|
||||||
* Returns the list of {@link Certificate Certificates}
|
* Returns the list of {@link Certificate Certificates}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
|
||||||
*
|
*
|
||||||
* @return the list of {@link Certificate Certificates}
|
* @return the list of {@link Certificate Certificates}
|
||||||
*/
|
*/
|
||||||
|
@ -256,8 +250,7 @@ public interface PrivilegeHandler {
|
||||||
/**
|
/**
|
||||||
* Returns all {@link RoleRep RoleReps}
|
* Returns all {@link RoleRep RoleReps}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
|
||||||
*
|
*
|
||||||
* @return the list of {@link RoleRep RoleReps}
|
* @return the list of {@link RoleRep RoleReps}
|
||||||
*/
|
*/
|
||||||
|
@ -266,8 +259,7 @@ public interface PrivilegeHandler {
|
||||||
/**
|
/**
|
||||||
* Returns all {@link UserRep UserReps}
|
* Returns all {@link UserRep UserReps}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
|
||||||
*
|
*
|
||||||
* @return the list of {@link UserRep UserReps}
|
* @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
|
* Method to query {@link UserRep} which meet the criteria set in the given {@link UserRep}. Null fields mean the
|
||||||
* fields are irrelevant.
|
* fields are irrelevant.
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 selectorRep
|
|
||||||
* the {@link UserRep} to use as criteria selection
|
|
||||||
*
|
*
|
||||||
* @return a list of {@link UserRep}s which fit the given criteria
|
* @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
|
* Removes the user with the given username
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
* @param username the username of the user to remove
|
||||||
* @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
|
* @return the {@link UserRep} of the user removed, or null if the user did not exist
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* if the user for this certificate may not perform the action
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* @throws PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate
|
|
||||||
*/
|
*/
|
||||||
UserRep removeUser(Certificate certificate, String username) throws PrivilegeException;
|
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
|
* Removes the role with the given roleName
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
* @param roleName the roleName of the role to remove
|
||||||
* @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
|
* @return the {@link RoleRep} of the role removed, or null if the role did not exist
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* 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
|
||||||
* @throws PrivilegeException
|
* user
|
||||||
* 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;
|
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>
|
* <p>
|
||||||
* Adds a new user with the information from this {@link UserRep}
|
* 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[])}
|
* the requirements of the implementation under {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 userRep
|
* @param password the password of the new user. If the password is null, then this is accepted but the user can
|
||||||
* the {@link UserRep} containing the information to create the new {@link User}
|
* not login, otherwise the password must be validated against
|
||||||
* @param password
|
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||||
* 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
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* 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 PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate or the user already exists
|
|
||||||
*/
|
*/
|
||||||
UserRep addUser(Certificate certificate, UserRep userRep, char[] password) throws PrivilegeException;
|
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,
|
* 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
|
* otherwise the user is created without a password
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 userReps
|
|
||||||
* the list of users to add or update
|
|
||||||
*/
|
*/
|
||||||
void addOrUpdateUsers(Certificate certificate, List<UserRep> userReps) throws PrivilegeException;
|
void addOrUpdateUsers(Certificate certificate, List<UserRep> userReps) throws PrivilegeException;
|
||||||
|
|
||||||
|
@ -410,108 +352,39 @@ public interface PrivilegeHandler {
|
||||||
* Any other fields will be ignored
|
* Any other fields will be ignored
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 userRep
|
* @param password the password of the new user. If the password is null, then this is accepted but the user can
|
||||||
* the {@link UserRep} with the fields set to their new values
|
* not login, otherwise the password must be validated against
|
||||||
|
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* 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 PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate or if the user does not exist
|
|
||||||
*/
|
*/
|
||||||
UserRep updateUser(Certificate certificate, UserRep userRep) throws PrivilegeException;
|
UserRep updateUser(Certificate certificate, UserRep userRep, char[] password) 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new role with the information from this {@link RoleRep}
|
* Adds a new role with the information from this {@link RoleRep}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 roleRep
|
|
||||||
* the {@link RoleRep} containing the information to create the new {@link Role}
|
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* 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 PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate or if the role already exists
|
|
||||||
*/
|
*/
|
||||||
RoleRep addRole(Certificate certificate, RoleRep roleRep) throws PrivilegeException;
|
RoleRep addRole(Certificate certificate, RoleRep roleRep) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces the existing role with the information from this {@link RoleRep}
|
* Replaces the existing role with the information from this {@link RoleRep}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 roleRep
|
|
||||||
* the {@link RoleRep} containing the information to replace the existing {@link Role}
|
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* 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 PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate or if the role does not exist
|
|
||||||
*/
|
*/
|
||||||
RoleRep replaceRole(Certificate certificate, RoleRep roleRep) throws PrivilegeException;
|
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>
|
* <p>
|
||||||
* Changes the password for the {@link User} with the given username. If the password is null, then the {@link User}
|
* 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
|
* It should be possible for a user to change their own password
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 username
|
* @param password the new password for this user. If the password is null, then the {@link User} can not login
|
||||||
* the username of the {@link User} for which the password is to be changed
|
* anymore. Otherwise the password must meet the requirements of the implementation under
|
||||||
* @param password
|
* {@link PrivilegeHandler#validatePassword(Locale, char[])}
|
||||||
* 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
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* if the user for this certificate may not perform the action
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* @throws PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate
|
|
||||||
*/
|
*/
|
||||||
void setUserPassword(Certificate certificate, String username, char[] password) throws PrivilegeException;
|
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
|
* Requires the given user to change their password after next login
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 username
|
|
||||||
* the username of the {@link User} for which the password change is requested
|
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* if the user for this certificate may not perform the action
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* @throws PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate
|
|
||||||
*/
|
*/
|
||||||
void requirePasswordChange(Certificate certificate, String username) throws PrivilegeException;
|
void requirePasswordChange(Certificate certificate, String username) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the {@link UserState} of the user
|
* Changes the {@link UserState} of the user
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 username
|
* @param state the new state for the user
|
||||||
* 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
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* if the user for this certificate may not perform the action
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* @throws PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate
|
|
||||||
*/
|
*/
|
||||||
UserRep setUserState(Certificate certificate, String username, UserState state) throws PrivilegeException;
|
UserRep setUserState(Certificate certificate, String username, UserState state) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the {@link Locale} of the user
|
* Changes the {@link Locale} of the user
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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 username
|
* @param locale the new {@link Locale} for the user
|
||||||
* 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
|
* @throws AccessDeniedException if the user for this certificate may not perform the action
|
||||||
* if the user for this certificate may not perform the action
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* @throws PrivilegeException
|
|
||||||
* if there is anything wrong with this certificate
|
|
||||||
*/
|
*/
|
||||||
UserRep setUserLocale(Certificate certificate, String username, Locale locale) throws PrivilegeException;
|
UserRep setUserLocale(Certificate certificate, String username, Locale locale) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate a password reset challenge for the given username
|
* Initiate a password reset challenge for the given username
|
||||||
*
|
*
|
||||||
* @param usage
|
* @param usage the usage for which the challenge is requested
|
||||||
* the usage for which the challenge is requested
|
* @param username the username of the user to initiate the challenge for
|
||||||
* @param username
|
|
||||||
* the username of the user to initiate the challenge for
|
|
||||||
*/
|
*/
|
||||||
void initiateChallengeFor(Usage usage, String username);
|
void initiateChallengeFor(Usage usage, String username);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate a password reset challenge for the given username
|
* Initiate a password reset challenge for the given username
|
||||||
*
|
*
|
||||||
* @param usage
|
* @param usage the usage for which the challenge is requested
|
||||||
* the usage for which the challenge is requested
|
* @param username the username of the user to initiate the challenge for
|
||||||
* @param username
|
* @param source the source of the challenge
|
||||||
* 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);
|
void initiateChallengeFor(Usage usage, String username, String source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the response of a challenge for the given username
|
* Validate the response of a challenge for the given username
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the username of the user for which the challenge is to be validated
|
||||||
* the username of the user for which the challenge is to be validated
|
* @param challenge the challenge from the user
|
||||||
* @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
|
* @return certificate with which the user can access the system with the {@link Usage} set to the value from the
|
||||||
* initiated challenge
|
* initiated challenge
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if anything goes wrong
|
||||||
* if anything goes wrong
|
|
||||||
*/
|
*/
|
||||||
Certificate validateChallenge(String username, String challenge) throws PrivilegeException;
|
Certificate validateChallenge(String username, String challenge) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the response of a challenge for the given username
|
* Validate the response of a challenge for the given username
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the username of the user for which the challenge is to be validated
|
||||||
* the username of the user for which the challenge is to be validated
|
* @param challenge the challenge from the user
|
||||||
* @param challenge
|
* @param source the source of the challenge validation
|
||||||
* 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
|
* @return certificate with which the user can access the system with the {@link Usage} set to the value from the
|
||||||
* initiated challenge
|
* initiated challenge
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if anything goes wrong
|
||||||
* if anything goes wrong
|
|
||||||
*/
|
*/
|
||||||
Certificate validateChallenge(String username, String challenge, String source) throws PrivilegeException;
|
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
|
* 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
|
* a {@link Certificate} with which this user may then perform actions
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||||
* 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
|
||||||
* @param password
|
* they must meet the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||||
* the password with which this user is to be authenticated. Null passwords are not accepted and they must meet
|
* @param keepAlive should this session be kept alive
|
||||||
* 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
|
* @return a {@link Certificate} with which this user may then perform actions
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user credentials are not valid
|
||||||
* if the user credentials are not valid
|
|
||||||
*/
|
*/
|
||||||
Certificate authenticate(String username, char[] password, boolean keepAlive) throws AccessDeniedException;
|
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
|
* 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
|
* a {@link Certificate} with which this user may then perform actions
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username the username of the {@link User} which is registered in the {@link PersistenceHandler}
|
||||||
* 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
|
||||||
* @param password
|
* they must meet the requirements of the {@link #validatePassword(Locale, char[])}-method
|
||||||
* the password with which this user is to be authenticated. Null passwords are not accepted and they must meet
|
* @param source the source of the authentication request, i.e. remote IP
|
||||||
* the requirements of the {@link #validatePassword(Locale, char[])}-method
|
* @param usage the usage type for this authentication
|
||||||
* @param source
|
* @param keepAlive should this session be kept alive
|
||||||
* 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
|
* @return a {@link Certificate} with which this user may then perform actions
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user credentials are not valid
|
||||||
* if the user credentials are not valid
|
|
||||||
*/
|
*/
|
||||||
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive)
|
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive)
|
||||||
throws AccessDeniedException;
|
throws AccessDeniedException;
|
||||||
|
@ -692,47 +524,37 @@ public interface PrivilegeHandler {
|
||||||
/**
|
/**
|
||||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||||
*
|
*
|
||||||
* @param data
|
* @param data the data to perform the SSO
|
||||||
* the data to perform the SSO
|
* @param keepAlive should this session be kept alive
|
||||||
* @param keepAlive
|
|
||||||
* should this session be kept alive
|
|
||||||
*
|
*
|
||||||
* @return the {@link Certificate} for the user
|
* @return the {@link Certificate} for the user
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if something goes wrong with the SSO
|
||||||
* if something goes wrong with the SSO
|
|
||||||
*/
|
*/
|
||||||
Certificate authenticateSingleSignOn(Object data, boolean keepAlive) throws PrivilegeException;
|
Certificate authenticateSingleSignOn(Object data, boolean keepAlive) throws PrivilegeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||||
*
|
*
|
||||||
* @param data
|
* @param data the data to perform the SSO
|
||||||
* the data to perform the SSO
|
* @param source the source of the SSO authentication
|
||||||
* @param source
|
* @param keepAlive may the certificate be kept alive
|
||||||
* the source of the SSO authentication
|
|
||||||
* @param keepAlive
|
|
||||||
* may the certificate be kept alive
|
|
||||||
*
|
*
|
||||||
* @return the {@link Certificate} for the user
|
* @return the {@link Certificate} for the user
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if something goes wrong with the SSO
|
||||||
* if something goes wrong with the SSO
|
|
||||||
*/
|
*/
|
||||||
Certificate authenticateSingleSignOn(Object data, String source, boolean keepAlive) throws PrivilegeException;
|
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
|
* Refreshes the given certificate's session with a new session, i.e. a new certificate
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the certificate for which to perform a refresh
|
||||||
* the certificate for which to perform a refresh
|
* @param source the source of the refresh request
|
||||||
* @param source
|
|
||||||
* the source of the refresh request
|
|
||||||
*
|
*
|
||||||
* @return a {@link Certificate} with which this user may then perform actions
|
* @return a {@link Certificate} with which this user may then perform actions
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the certificate is now valid, or refreshing is not allowed
|
||||||
* if the certificate is now valid, or refreshing is not allowed
|
|
||||||
*/
|
*/
|
||||||
Certificate refresh(Certificate certificate, String source) throws AccessDeniedException;
|
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
|
* 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}
|
* with the credentials associated to the given {@link Certificate}
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} for which the session is to be invalidated
|
||||||
* 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
|
* @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
|
* 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
|
* actions and do not need to access the {@link PrivilegeHandler} anymore
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} to check
|
||||||
* the {@link Certificate} to check
|
|
||||||
*
|
*
|
||||||
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* if there is anything wrong with this certificate
|
* @throws NotAuthenticatedException if the certificate has expired
|
||||||
* @throws NotAuthenticatedException
|
|
||||||
* if the certificate has expired
|
|
||||||
*/
|
*/
|
||||||
PrivilegeContext validate(Certificate certificate) throws PrivilegeException;
|
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}
|
* system user session and that the user exists for the certificate. This method checks if the {@link Certificate}
|
||||||
* has been tampered with
|
* has been tampered with
|
||||||
*
|
*
|
||||||
* @param ctx
|
* @param ctx the {@link PrivilegeContext} to check
|
||||||
* the {@link PrivilegeContext} to check
|
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if there is anything wrong with this privilege context
|
||||||
* if there is anything wrong with this privilege context
|
* @throws NotAuthenticatedException if the privilege context has expired
|
||||||
* @throws NotAuthenticatedException
|
|
||||||
* if the privilege context has expired
|
|
||||||
*/
|
*/
|
||||||
void validateSystemSession(PrivilegeContext ctx) throws PrivilegeException;
|
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
|
* 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
|
* actions and do not need to access the {@link PrivilegeHandler} anymore
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} to check
|
||||||
* the {@link Certificate} to check
|
* @param source the source, e.g. remote IP for this validation request
|
||||||
* @param source
|
|
||||||
* the source, e.g. remote IP for this validation request
|
|
||||||
*
|
*
|
||||||
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
* @return the {@link PrivilegeContext} for the given {@link Certificate}
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if there is anything wrong with this certificate
|
||||||
* if there is anything wrong with this certificate
|
* @throws NotAuthenticatedException if the certificate has expired
|
||||||
* @throws NotAuthenticatedException
|
|
||||||
* if the certificate has expired
|
|
||||||
*/
|
*/
|
||||||
PrivilegeContext validate(Certificate certificate, String source) throws PrivilegeException;
|
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
|
* <b>Note:</b> It depends on the underlying {@link PersistenceHandler} implementation if data really is read
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
* @param source the source of the request
|
||||||
* @param source
|
|
||||||
* the source of the request
|
|
||||||
*
|
*
|
||||||
* @return true if the reload was successful, false if something went wrong
|
* @return true if the reload was successful, false if something went wrong
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||||
* if the users of the given certificate does not have the privilege to perform this action
|
* action
|
||||||
*/
|
*/
|
||||||
boolean reload(Certificate certificate, String source);
|
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
|
* Persists any changes to the privilege data model. Changes are thus not persisted immediately, but must be
|
||||||
* actively performed
|
* actively performed
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* 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
|
* @return true if changes were persisted, false if no changes were persisted
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||||
* if the users of the given certificate does not have the privilege to perform this action
|
* action
|
||||||
*/
|
*/
|
||||||
boolean persist(Certificate certificate) throws AccessDeniedException;
|
boolean persist(Certificate certificate) throws AccessDeniedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persists all currently active sessions
|
* Persists all currently active sessions
|
||||||
*
|
*
|
||||||
* @param certificate
|
* @param certificate the {@link Certificate} of the user which has the privilege to perform this action
|
||||||
* the {@link Certificate} of the user which has the privilege to perform this action
|
* @param source the source of the request
|
||||||
* @param source
|
|
||||||
* the source of the request
|
|
||||||
*
|
*
|
||||||
* @return true if changes were persisted, false if not (i.e. not enabled)
|
* @return true if changes were persisted, false if not (i.e. not enabled)
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the users of the given certificate does not have the privilege to perform this
|
||||||
* if the users of the given certificate does not have the privilege to perform this action
|
* action
|
||||||
*/
|
*/
|
||||||
boolean persistSessions(Certificate certificate, String source) throws AccessDeniedException;
|
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
|
* has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation
|
||||||
* of the given {@link SystemAction} instance
|
* of the given {@link SystemAction} instance
|
||||||
*
|
*
|
||||||
* @param systemUsername
|
* @param systemUsername the username of the system user to perform the action as
|
||||||
* the username of the system user to perform the action as
|
* @param action the action to be performed as the system user
|
||||||
* @param action
|
|
||||||
* the action to be performed as the system user
|
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||||
* if the user does not exist, or the system action is not allowed
|
* @throws Exception if anything else goes wrong during execution
|
||||||
* @throws Exception
|
|
||||||
* if anything else goes wrong during execution
|
|
||||||
*/
|
*/
|
||||||
void runAs(String systemUsername, SystemAction action) throws PrivilegeException, Exception;
|
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
|
* has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation
|
||||||
* of the given {@link SystemAction} instance
|
* of the given {@link SystemAction} instance
|
||||||
*
|
*
|
||||||
* @param systemUsername
|
* @param systemUsername the username of the system user to perform the action as
|
||||||
* the username of the system user to perform the action as
|
* @param action the action to be performed as the system user
|
||||||
* @param action
|
|
||||||
* the action to be performed as the system user
|
|
||||||
*
|
*
|
||||||
* @return the action
|
* @return the action
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||||
* if the user does not exist, or the system action is not allowed
|
* @throws Exception if anything else goes wrong during execution
|
||||||
* @throws Exception
|
|
||||||
* if anything else goes wrong during execution
|
|
||||||
*/
|
*/
|
||||||
<T> T runWithResult(String systemUsername, SystemActionWithResult<T> action) throws PrivilegeException, Exception;
|
<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} should be open for a longer period of time, or where opening many
|
||||||
* {@link PrivilegeContext} is resource intensive e.g. on low power devices.
|
* {@link PrivilegeContext} is resource intensive e.g. on low power devices.
|
||||||
*
|
*
|
||||||
* @param systemUsername
|
* @param systemUsername the username of the system user to perform the action as
|
||||||
* the username of the system user to perform the action as
|
|
||||||
*
|
*
|
||||||
* @return the action
|
* @return the action
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if the user does not exist, or the system action is not allowed
|
||||||
* if the user does not exist, or the system action is not allowed
|
|
||||||
*/
|
*/
|
||||||
PrivilegeContext openSystemUserContext(String systemUsername) throws PrivilegeException;
|
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;
|
package li.strolch.privilege.handler;
|
||||||
|
|
||||||
import static java.text.MessageFormat.format;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
|
import li.strolch.privilege.helper.XmlConstants;
|
||||||
import static li.strolch.privilege.helper.XmlConstants.*;
|
import li.strolch.privilege.model.internal.Group;
|
||||||
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
|
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.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import static java.lang.Boolean.parseBoolean;
|
||||||
import li.strolch.privilege.helper.XmlConstants;
|
import static java.text.MessageFormat.format;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import static li.strolch.privilege.helper.XmlConstants.*;
|
||||||
import li.strolch.privilege.xml.PrivilegeRolesDomWriter;
|
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
|
||||||
import li.strolch.privilege.xml.PrivilegeRolesSaxReader;
|
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link PersistenceHandler} implementation which reads the configuration from XML files. These configuration is passed
|
* {@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);
|
protected static final Logger logger = LoggerFactory.getLogger(XmlPersistenceHandler.class);
|
||||||
|
|
||||||
private final Map<String, User> userMap;
|
private final Map<String, User> userMap;
|
||||||
|
private final Map<String, Group> groupMap;
|
||||||
private final Map<String, Role> roleMap;
|
private final Map<String, Role> roleMap;
|
||||||
|
|
||||||
private boolean userMapDirty;
|
private boolean userMapDirty;
|
||||||
|
private boolean groupMapDirty;
|
||||||
private boolean roleMapDirty;
|
private boolean roleMapDirty;
|
||||||
|
|
||||||
private Map<String, String> parameterMap;
|
private Map<String, String> parameterMap;
|
||||||
|
|
||||||
private File usersPath;
|
private File usersPath;
|
||||||
|
private File groupsPath;
|
||||||
private File rolesPath;
|
private File rolesPath;
|
||||||
|
|
||||||
private boolean caseInsensitiveUsername;
|
private boolean caseInsensitiveUsername;
|
||||||
|
|
||||||
public XmlPersistenceHandler() {
|
public XmlPersistenceHandler() {
|
||||||
this.roleMap = new ConcurrentHashMap<>();
|
this.roleMap = new ConcurrentHashMap<>();
|
||||||
|
this.groupMap = new ConcurrentHashMap<>();
|
||||||
this.userMap = 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
|
@Override
|
||||||
public List<Role> getAllRoles() {
|
public List<Role> getAllRoles() {
|
||||||
synchronized (this.roleMap) {
|
synchronized (this.roleMap) {
|
||||||
|
@ -91,6 +104,11 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
return this.userMap.get(this.caseInsensitiveUsername ? username.toLowerCase() : username);
|
return this.userMap.get(this.caseInsensitiveUsername ? username.toLowerCase() : username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Group getGroup(String groupName) {
|
||||||
|
return this.groupMap.get(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Role getRole(String roleName) {
|
public Role getRole(String roleName) {
|
||||||
return this.roleMap.get(roleName);
|
return this.roleMap.get(roleName);
|
||||||
|
@ -103,6 +121,13 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Group removeGroup(String groupName) {
|
||||||
|
Group group = this.groupMap.remove(groupName);
|
||||||
|
this.groupMapDirty = group != null;
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Role removeRole(String roleName) {
|
public Role removeRole(String roleName) {
|
||||||
Role role = this.roleMap.remove(roleName);
|
Role role = this.roleMap.remove(roleName);
|
||||||
|
@ -129,6 +154,23 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
this.userMapDirty = true;
|
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
|
@Override
|
||||||
public void addRole(Role role) {
|
public void addRole(Role role) {
|
||||||
if (this.roleMap.containsKey(role.getName()))
|
if (this.roleMap.containsKey(role.getName()))
|
||||||
|
@ -149,9 +191,10 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
/**
|
/**
|
||||||
* Initializes this {@link XmlPersistenceHandler} by reading the following parameters:
|
* Initializes this {@link XmlPersistenceHandler} by reading the following parameters:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link XmlConstants#XML_PARAM_BASE_PATH}</li>
|
* <li>{@link XmlConstants#PARAM_BASE_PATH}</li>
|
||||||
* <li>{@link XmlConstants#XML_PARAM_USERS_FILE}</li>
|
* <li>{@link XmlConstants#PARAM_USERS_FILE}</li>
|
||||||
* <li>{@link XmlConstants#XML_PARAM_ROLES_FILE}</li>
|
* <li>{@link XmlConstants#PARAM_GROUPS_FILE}</li>
|
||||||
|
* <li>{@link XmlConstants#PARAM_ROLES_FILE}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -159,58 +202,50 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
this.parameterMap = Map.copyOf(paramsMap);
|
this.parameterMap = Map.copyOf(paramsMap);
|
||||||
|
|
||||||
// get and validate base bath
|
// 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);
|
File basePathF = new File(basePath);
|
||||||
if (!basePathF.exists() && !basePathF.isDirectory()) {
|
if (!basePathF.exists() && !basePathF.isDirectory()) {
|
||||||
String msg = "[{0}] Defined parameter {1} does not point to a valid path at {2}";
|
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);
|
throw new PrivilegeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get users file name
|
File usersPath = getFile(basePath, PARAM_USERS_FILE, PARAM_USERS_FILE_DEF, true);
|
||||||
String usersFileName = this.parameterMap.get(XML_PARAM_USERS_FILE);
|
File groupsPath = getFile(basePath, PARAM_GROUPS_FILE, PARAM_GROUPS_FILE_DEF, false);
|
||||||
if (StringHelper.isEmpty(usersFileName)) {
|
File rolesPath = getFile(basePath, PARAM_ROLES_FILE, PARAM_ROLES_FILE_DEF, true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save path to model
|
// save path to model
|
||||||
this.usersPath = usersPath;
|
this.usersPath = usersPath;
|
||||||
|
this.groupsPath = groupsPath;
|
||||||
this.rolesPath = rolesPath;
|
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())
|
if (reload())
|
||||||
logger.info("Privilege Data loaded.");
|
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
|
* Reads the XML configuration files which contain the model. Which configuration files are parsed was defined in
|
||||||
* the while calling {@link #initialize(Map)}
|
* the while calling {@link #initialize(Map)}
|
||||||
|
@ -224,6 +259,10 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
PrivilegeUsersSaxReader usersXmlHandler = new PrivilegeUsersSaxReader(this.caseInsensitiveUsername);
|
PrivilegeUsersSaxReader usersXmlHandler = new PrivilegeUsersSaxReader(this.caseInsensitiveUsername);
|
||||||
XmlHelper.parseDocument(this.usersPath, usersXmlHandler);
|
XmlHelper.parseDocument(this.usersPath, usersXmlHandler);
|
||||||
|
|
||||||
|
PrivilegeGroupsSaxReader groupsXmlHandler = new PrivilegeGroupsSaxReader();
|
||||||
|
if (this.groupsPath.exists())
|
||||||
|
XmlHelper.parseDocument(this.groupsPath, groupsXmlHandler);
|
||||||
|
|
||||||
PrivilegeRolesSaxReader rolesXmlHandler = new PrivilegeRolesSaxReader();
|
PrivilegeRolesSaxReader rolesXmlHandler = new PrivilegeRolesSaxReader();
|
||||||
XmlHelper.parseDocument(this.rolesPath, rolesXmlHandler);
|
XmlHelper.parseDocument(this.rolesPath, rolesXmlHandler);
|
||||||
|
|
||||||
|
@ -233,6 +272,12 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
this.roleMap.putAll(rolesXmlHandler.getRoles());
|
this.roleMap.putAll(rolesXmlHandler.getRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GROUPS
|
||||||
|
synchronized (this.groupMap) {
|
||||||
|
this.groupMap.clear();
|
||||||
|
this.groupMap.putAll(groupsXmlHandler.getGroups());
|
||||||
|
}
|
||||||
|
|
||||||
// USERS
|
// USERS
|
||||||
synchronized (this.userMap) {
|
synchronized (this.userMap) {
|
||||||
this.userMap.clear();
|
this.userMap.clear();
|
||||||
|
@ -240,21 +285,40 @@ public class XmlPersistenceHandler implements PersistenceHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userMapDirty = false;
|
this.userMapDirty = false;
|
||||||
|
this.groupMapDirty = false;
|
||||||
this.roleMapDirty = false;
|
this.roleMapDirty = false;
|
||||||
|
|
||||||
logger.info(format("Read {0} Users", this.userMap.size()));
|
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()));
|
logger.info(format("Read {0} Roles", this.roleMap.size()));
|
||||||
|
|
||||||
// validate referenced roles exist
|
// validate referenced elements exist
|
||||||
for (User user : this.userMap.values()) {
|
for (User user : this.userMap.values()) {
|
||||||
for (String roleName : user.getRoles()) {
|
for (String roleName : user.getRoles()) {
|
||||||
|
|
||||||
// validate that role exists
|
// validate that role exists
|
||||||
if (getRole(roleName) == null) {
|
if (getRole(roleName) == null) {
|
||||||
logger.error(
|
logger.error(
|
||||||
format("Role {0} does not exist referenced by user {1}", roleName, user.getUsername()));
|
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;
|
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)}
|
* Writes the model to the XML files. Where the files are written to was defined in the {@link #initialize(Map)}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean persist() {
|
public boolean persist() throws XMLStreamException, IOException {
|
||||||
|
|
||||||
long start = System.nanoTime();
|
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;
|
boolean saved = false;
|
||||||
|
|
||||||
// get users file
|
// write users file
|
||||||
if (this.userMapDirty) {
|
if (this.userMapDirty) {
|
||||||
// delegate writing
|
new PrivilegeUsersSaxWriter(getAllUsers(), this.usersPath).write();
|
||||||
PrivilegeUsersDomWriter modelWriter = new PrivilegeUsersDomWriter(getAllUsers(), this.usersPath);
|
|
||||||
modelWriter.write();
|
|
||||||
|
|
||||||
this.userMapDirty = false;
|
this.userMapDirty = false;
|
||||||
saved = true;
|
saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get roles file
|
// write groups file
|
||||||
if (this.roleMapDirty) {
|
if (this.groupMapDirty) {
|
||||||
// delegate writing
|
new PrivilegeGroupsSaxWriter(getAllGroups(), this.groupsPath).write();
|
||||||
PrivilegeRolesDomWriter modelWriter = new PrivilegeRolesDomWriter(getAllRoles(), this.rolesPath);
|
this.groupMapDirty = false;
|
||||||
modelWriter.write();
|
saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write roles file
|
||||||
|
if (this.roleMapDirty) {
|
||||||
|
new PrivilegeRolesSaxWriter(getAllRoles(), this.rolesPath).write();
|
||||||
this.roleMapDirty = false;
|
this.roleMapDirty = false;
|
||||||
saved = true;
|
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;
|
return saved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||||
import static li.strolch.privilege.model.internal.PasswordCrypt.buildPasswordString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -111,9 +110,9 @@ public class PasswordCreator {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> parameterMap = new HashMap<>();
|
Map<String, String> parameterMap = new HashMap<>();
|
||||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_ALGORITHM, hashAlgorithm);
|
parameterMap.put(XmlConstants.PARAM_HASH_ALGORITHM, hashAlgorithm);
|
||||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_ITERATIONS, String.valueOf(iterations));
|
parameterMap.put(XmlConstants.PARAM_HASH_ITERATIONS, String.valueOf(iterations));
|
||||||
parameterMap.put(XmlConstants.XML_PARAM_HASH_KEY_LENGTH, String.valueOf(keyLength));
|
parameterMap.put(XmlConstants.PARAM_HASH_KEY_LENGTH, String.valueOf(keyLength));
|
||||||
|
|
||||||
DefaultEncryptionHandler encryptionHandler = new DefaultEncryptionHandler();
|
DefaultEncryptionHandler encryptionHandler = new DefaultEncryptionHandler();
|
||||||
encryptionHandler.initialize(parameterMap);
|
encryptionHandler.initialize(parameterMap);
|
||||||
|
@ -136,15 +135,15 @@ public class PasswordCreator {
|
||||||
byte[] salt = saltS.getBytes();
|
byte[] salt = saltS.getBytes();
|
||||||
|
|
||||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, salt);
|
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("Hash is: " + passwordHashS);
|
||||||
System.out.println("Salt is: " + saltS);
|
System.out.println("Salt is: " + saltS);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
||||||
System.out.println(
|
System.out.println(
|
||||||
XmlConstants.XML_ATTR_PASSWORD + "=\"" + passwordHashS + "\" " + XmlConstants.XML_ATTR_SALT +
|
XmlConstants.ATTR_PASSWORD + "=\"" + passwordHashS + "\" " + XmlConstants.ATTR_SALT + "=\"" +
|
||||||
"=\"" + saltS + "\"");
|
saltS + "\"");
|
||||||
System.out.println(XmlConstants.XML_ATTR_PASSWORD + "=\"" + passwordCrypt.buildPasswordString() + "\"");
|
System.out.println(XmlConstants.ATTR_PASSWORD + "=\"" + passwordCrypt.buildPasswordString() + "\"");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
package li.strolch.privilege.helper;
|
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.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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 class WriteRolesFileHelper {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws XMLStreamException, IOException {
|
||||||
|
|
||||||
if (args.length != 2)
|
if (args.length != 2)
|
||||||
throw new IllegalStateException("Usage: <src> <dst>");
|
throw new IllegalStateException("Usage: <src> <dst>");
|
||||||
|
@ -31,7 +33,7 @@ public class WriteRolesFileHelper {
|
||||||
Map<String, Role> rolesMap = xmlHandler.getRoles();
|
Map<String, Role> rolesMap = xmlHandler.getRoles();
|
||||||
List<Role> roles = new ArrayList<>(rolesMap.values());
|
List<Role> roles = new ArrayList<>(rolesMap.values());
|
||||||
|
|
||||||
PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, dst);
|
PrivilegeRolesSaxWriter configSaxWriter = new PrivilegeRolesSaxWriter(roles, dst);
|
||||||
configSaxWriter.write();
|
configSaxWriter.write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,298 +23,69 @@ package li.strolch.privilege.helper;
|
||||||
@SuppressWarnings("nls")
|
@SuppressWarnings("nls")
|
||||||
public class XmlConstants {
|
public class XmlConstants {
|
||||||
|
|
||||||
/**
|
public static final String ROOT_PRIVILEGE = "Privilege";
|
||||||
* XML_ROOT_PRIVILEGE_CONTAINER = "PrivilegeContainer" :
|
public static final String CONTAINER = "Container";
|
||||||
*/
|
public static final String POLICIES = "Policies";
|
||||||
public static final String XML_ROOT_PRIVILEGE = "Privilege";
|
public static final String PRIVILEGES = "Privileges";
|
||||||
|
public static final String ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles";
|
||||||
/**
|
public static final String ROOT_CERTIFICATES = "Certificates";
|
||||||
* XML_CONTAINER = "Container" :
|
public static final String HANDLER_USER_CHALLENGE = "UserChallengeHandler";
|
||||||
*/
|
public static final String HANDLER_PERSISTENCE = "PersistenceHandler";
|
||||||
public static final String XML_CONTAINER = "Container";
|
public static final String HANDLER_ENCRYPTION = "EncryptionHandler";
|
||||||
|
public static final String HANDLER_PASSWORD_STRENGTH = "PasswordStrengthHandler";
|
||||||
/**
|
public static final String HANDLER_SSO = "SsoHandler";
|
||||||
* XML_POLICIES = "Policies" :
|
public static final String HANDLER_PRIVILEGE = "PrivilegeHandler";
|
||||||
*/
|
public static final String ROLES = "Roles";
|
||||||
public static final String XML_POLICIES = "Policies";
|
public static final String ROLE = "Role";
|
||||||
|
public static final String USERS = "Users";
|
||||||
/**
|
public static final String GROUPS = "Groups";
|
||||||
* XML_PRIVILEGES = "Privileges" :
|
public static final String GROUP = "Group";
|
||||||
*/
|
public static final String CERTIFICATE = "Certificate";
|
||||||
public static final String XML_PRIVILEGES = "Privileges";
|
public static final String SESSION_DATA = "SessionData";
|
||||||
|
public static final String USER = "User";
|
||||||
/**
|
public static final String HISTORY = "History";
|
||||||
* XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles" :
|
public static final String FIRST_LOGIN = "FirstLogin";
|
||||||
*/
|
public static final String LAST_LOGIN = "LastLogin";
|
||||||
public static final String XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles";
|
public static final String LAST_PASSWORD_CHANGE = "LastPasswordChange";
|
||||||
|
public static final String PASSWORD_CHANGE_REQUESTED = "PasswordChangeRequested";
|
||||||
/**
|
public static final String PRIVILEGE = "Privilege";
|
||||||
* XML_ROOT_CERTIFICATES = "Certificates" :
|
public static final String POLICY = "Policy";
|
||||||
*/
|
public static final String PARAMETERS = "Parameters";
|
||||||
public static final String XML_ROOT_CERTIFICATES = "Certificates";
|
public static final String PARAMETER = "Parameter";
|
||||||
|
public static final String PROPERTIES = "Properties";
|
||||||
/**
|
public static final String PROPERTY = "Property";
|
||||||
* XML_HANDLER_USER_CHALLENGE = "UserChallengeHandler" :
|
public static final String ALL_ALLOWED = "AllAllowed";
|
||||||
*/
|
public static final String DENY = "Deny";
|
||||||
public static final String XML_HANDLER_USER_CHALLENGE = "UserChallengeHandler";
|
public static final String ALLOW = "Allow";
|
||||||
|
public static final String FIRSTNAME = "Firstname";
|
||||||
/**
|
public static final String LASTNAME = "Lastname";
|
||||||
* XML_HANDLER_PERSISTENCE = "PersistenceHandler" :
|
public static final String STATE = "State";
|
||||||
*/
|
public static final String LOCALE = "Locale";
|
||||||
public static final String XML_HANDLER_PERSISTENCE = "PersistenceHandler";
|
public static final String ATTR_CLASS = "class";
|
||||||
|
public static final String ATTR_LOGIN_TIME = "loginTime";
|
||||||
/**
|
public static final String ATTR_KEEP_ALIVE = "keepAlive";
|
||||||
* XML_HANDLER_ENCRYPTION = "EncryptionHandler" :
|
public static final String ATTR_LAST_ACCESS = "lastAccess";
|
||||||
*/
|
public static final String ATTR_NAME = "name";
|
||||||
public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler";
|
public static final String ATTR_VALUE = "value";
|
||||||
|
public static final String ATTR_POLICY = "policy";
|
||||||
/**
|
public static final String ATTR_USER_ID = "userId";
|
||||||
* XML_HANDLER_ENCRYPTION = "PasswordStrengthHandler" :
|
public static final String ATTR_SESSION_ID = "sessionId";
|
||||||
*/
|
public static final String ATTR_USAGE = "usage";
|
||||||
public static final String XML_HANDLER_PASSWORD_STRENGTH = "PasswordStrengthHandler";
|
public static final String ATTR_USERNAME = "username";
|
||||||
|
public static final String ATTR_AUTH_TOKEN = "authToken";
|
||||||
/**
|
public static final String ATTR_SOURCE = "source";
|
||||||
* XML_HANDLER_ENCRYPTION = "SsoHandler" :
|
public static final String ATTR_LOCALE = "locale";
|
||||||
*/
|
public static final String ATTR_PASSWORD = "password";
|
||||||
public static final String XML_HANDLER_SSO = "SsoHandler";
|
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";
|
||||||
* XML_HANDLER_PRIVILEGE = "PrivilegeHandler" :
|
public static final String PARAM_HASH_ITERATIONS = "hashIterations";
|
||||||
*/
|
public static final String PARAM_HASH_KEY_LENGTH = "hashKeyLength";
|
||||||
public static final String XML_HANDLER_PRIVILEGE = "PrivilegeHandler";
|
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";
|
||||||
* XML_ROLES = "Roles" :
|
public static final String PARAM_GROUPS_FILE_DEF = "PrivilegeGroups.xml";
|
||||||
*/
|
public static final String PARAM_ROLES_FILE = "rolesXmlFile";
|
||||||
public static final String XML_ROLES = "Roles";
|
public static final String PARAM_ROLES_FILE_DEF = "PrivilegeRoles.xml";
|
||||||
|
public static final String PARAM_BASE_PATH = "basePath";
|
||||||
/**
|
|
||||||
* 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";
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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.time.ZonedDateTime;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import li.strolch.privilege.base.PrivilegeConstants;
|
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
|
||||||
import li.strolch.privilege.model.internal.User;
|
|
||||||
import li.strolch.utils.helper.StringHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link Certificate} is the object a client keeps when accessing a Privilege enabled system. This object is the
|
* 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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public final class Certificate implements Serializable {
|
public final class Certificate {
|
||||||
|
|
||||||
private final Usage usage;
|
private final Usage usage;
|
||||||
private final String sessionId;
|
private final String sessionId;
|
||||||
|
@ -50,6 +48,7 @@ public final class Certificate implements Serializable {
|
||||||
private final ZonedDateTime loginTime;
|
private final ZonedDateTime loginTime;
|
||||||
private final boolean keepAlive;
|
private final boolean keepAlive;
|
||||||
|
|
||||||
|
private final Set<String> userGroups;
|
||||||
private final Set<String> userRoles;
|
private final Set<String> userRoles;
|
||||||
private final Map<String, String> propertyMap;
|
private final Map<String, String> propertyMap;
|
||||||
|
|
||||||
|
@ -64,49 +63,28 @@ public final class Certificate implements Serializable {
|
||||||
* by the {@link PrivilegeHandler}
|
* by the {@link PrivilegeHandler}
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param usage
|
* @param usage the usage allowed for this certificate
|
||||||
* the usage allowed for this certificate
|
* @param sessionId the users session id
|
||||||
* @param sessionId
|
* @param username the users login name
|
||||||
* the users session id
|
* @param firstName the users first name
|
||||||
* @param username
|
* @param lastName the users last name
|
||||||
* the users login name
|
* @param authToken the authentication token defining the users unique session and is a private field of this
|
||||||
* @param firstName
|
* certificate.
|
||||||
* the users first name
|
* @param locale the users {@link Locale}
|
||||||
* @param lastName
|
* @param userRoles the user's roles
|
||||||
* the users last name
|
* @param propertyMap a {@link Map} containing string value pairs of properties for the logged in user. These
|
||||||
* @param authToken
|
* properties can be edited and can be used for the user to change settings of this session
|
||||||
* 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,
|
public Certificate(Usage usage, String sessionId, String username, String firstName, String lastName,
|
||||||
UserState userState, String authToken, String source, ZonedDateTime loginTime, boolean keepAlive,
|
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
|
DBC.PRE.assertNotEmpty("sessionId must not be empty", sessionId);
|
||||||
if (StringHelper.isEmpty(sessionId)) {
|
DBC.PRE.assertNotEmpty("username must not be empty", username);
|
||||||
throw new PrivilegeException("sessionId is null!");
|
DBC.PRE.assertNotEmpty("authToken must not be empty", authToken);
|
||||||
}
|
DBC.PRE.assertNotNull("userState must not be empty", userState);
|
||||||
if (StringHelper.isEmpty(username)) {
|
DBC.PRE.assertNotNull("usage must not be empty", usage);
|
||||||
throw new PrivilegeException("username is null!");
|
DBC.PRE.assertNotNull("source must not be null", source);
|
||||||
}
|
|
||||||
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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.usage = usage;
|
this.usage = usage;
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
|
@ -126,11 +104,12 @@ public final class Certificate implements Serializable {
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
|
|
||||||
if (propertyMap == null)
|
if (propertyMap == null)
|
||||||
this.propertyMap = Collections.emptyMap();
|
this.propertyMap = Map.of();
|
||||||
else
|
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();
|
this.lastAccess = ZonedDateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,15 +129,29 @@ public final class Certificate implements Serializable {
|
||||||
return this.usage;
|
return this.usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getUserGroups() {
|
||||||
|
return this.userGroups;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getUserRoles() {
|
public Set<String> getUserRoles() {
|
||||||
return this.userRoles;
|
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
|
* Returns true if the user of this certificate has the given role
|
||||||
*
|
*
|
||||||
* @param role
|
* @param role the role to check for
|
||||||
* the role to check for
|
|
||||||
*
|
*
|
||||||
* @return true if the user of this certificate has the given role
|
* @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
|
* Returns the property with the given key
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key the key for which the property is to be returned
|
||||||
* the key for which the property is to be returned
|
|
||||||
*
|
*
|
||||||
* @return the value of the property with the given key, or null if it does not exist
|
* @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(", username=");
|
||||||
builder.append(this.username);
|
builder.append(this.username);
|
||||||
|
|
||||||
if (StringHelper.isNotEmpty(this.firstname)) {
|
if (isNotEmpty(this.firstname)) {
|
||||||
builder.append(", firstname=");
|
builder.append(", firstname=");
|
||||||
builder.append(this.firstname);
|
builder.append(this.firstname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringHelper.isNotEmpty(this.lastname)) {
|
if (isNotEmpty(this.lastname)) {
|
||||||
builder.append(", lastname=");
|
builder.append(", lastname=");
|
||||||
builder.append(this.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;
|
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.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import li.strolch.privilege.base.AccessDeniedException;
|
import static java.text.MessageFormat.format;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import static li.strolch.privilege.i18n.PrivilegeMessages.getString;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
|
||||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -36,19 +38,15 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @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) {
|
||||||
|
|
||||||
//
|
public PrivilegeContext(UserRep userRep, Certificate certificate, Map<String, Privilege> privileges,
|
||||||
// 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,
|
|
||||||
Map<String, PrivilegePolicy> policies) {
|
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.userRep = userRep;
|
||||||
this.certificate = certificate;
|
this.certificate = certificate;
|
||||||
this.privileges = Map.copyOf(privileges);
|
this.privileges = Map.copyOf(privileges);
|
||||||
|
@ -85,35 +83,64 @@ public class PrivilegeContext {
|
||||||
|
|
||||||
public void assertHasPrivilege(String privilegeName) throws AccessDeniedException {
|
public void assertHasPrivilege(String privilegeName) throws AccessDeniedException {
|
||||||
if (!this.privileges.containsKey(privilegeName)) {
|
if (!this.privileges.containsKey(privilegeName)) {
|
||||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"),
|
String msg = format(getString("Privilege.noprivilege.user"), userRep.getUsername(), privilegeName);
|
||||||
userRep.getUsername(), privilegeName);
|
|
||||||
throw new AccessDeniedException(msg);
|
throw new AccessDeniedException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasGroup(String groupName) {
|
||||||
|
return this.userRep.hasGroup(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasRole(String roleName) {
|
public boolean hasRole(String roleName) {
|
||||||
return this.userRep.hasRole(roleName);
|
return this.userRep.hasRole(roleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasRole(String roleName) throws AccessDeniedException {
|
public void assertHasGroup(String groupName) throws AccessDeniedException {
|
||||||
if (!this.userRep.hasRole(roleName)) {
|
if (!this.userRep.hasGroup(groupName)) {
|
||||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.role"),
|
String msg = format(getString("Privilege.noprivilege.group"), userRep.getUsername(), groupName);
|
||||||
userRep.getUsername(), roleName);
|
|
||||||
throw new AccessDeniedException(msg);
|
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 {
|
public void assertHasAnyRole(String... roleNames) throws AccessDeniedException {
|
||||||
for (String roleName : roleNames) {
|
for (String roleName : roleNames) {
|
||||||
if (this.userRep.hasRole(roleName))
|
if (this.userRep.hasRole(roleName))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.role"),
|
String msg = format(getString("Privilege.noprivilege.role"), userRep.getUsername(),
|
||||||
userRep.getUsername(), String.join(", ", roleNames));
|
String.join(", ", roleNames));
|
||||||
throw new AccessDeniedException(msg);
|
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 {
|
public boolean hasAnyRole(String... roleNames) throws AccessDeniedException {
|
||||||
for (String roleName : roleNames) {
|
for (String roleName : roleNames) {
|
||||||
if (this.userRep.hasRole(roleName))
|
if (this.userRep.hasRole(roleName))
|
||||||
|
@ -123,7 +150,7 @@ public class PrivilegeContext {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPrivilege getPrivilege(String privilegeName) throws AccessDeniedException {
|
public Privilege getPrivilege(String privilegeName) throws AccessDeniedException {
|
||||||
assertHasPrivilege(privilegeName);
|
assertHasPrivilege(privilegeName);
|
||||||
return this.privileges.get(privilegeName);
|
return this.privileges.get(privilegeName);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +159,7 @@ public class PrivilegeContext {
|
||||||
PrivilegePolicy policy = this.policies.get(policyName);
|
PrivilegePolicy policy = this.policies.get(policyName);
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
String msg = "The PrivilegePolicy {0} does not exist on the PrivilegeContext!";
|
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;
|
return policy;
|
||||||
}
|
}
|
||||||
|
@ -148,15 +175,12 @@ public class PrivilegeContext {
|
||||||
*
|
*
|
||||||
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
||||||
*
|
*
|
||||||
* @param privilegeName
|
* @param privilegeName the name of the privilege to verify
|
||||||
* the name of the privilege to verify
|
* @param privilegeValue the value
|
||||||
* @param privilegeValue
|
|
||||||
* the value
|
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user does not have access
|
||||||
* if the user does not have access
|
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||||
* @throws PrivilegeException
|
* errors
|
||||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
|
||||||
*/
|
*/
|
||||||
public void validateAction(String privilegeName, String privilegeValue)
|
public void validateAction(String privilegeName, String privilegeValue)
|
||||||
throws PrivilegeException, AccessDeniedException {
|
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,
|
* 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.
|
* then a {@link AccessDeniedException} is thrown.
|
||||||
*
|
*
|
||||||
* @param restrictable
|
* @param restrictable the {@link Restrictable} which the user wants to access
|
||||||
* the {@link Restrictable} which the user wants to access
|
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException if the user does not have access
|
||||||
* if the user does not have access
|
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||||
* @throws PrivilegeException
|
* errors
|
||||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
|
||||||
*/
|
*/
|
||||||
public void validateAction(Restrictable restrictable) throws PrivilegeException, AccessDeniedException {
|
public void validateAction(Restrictable restrictable) throws PrivilegeException, AccessDeniedException {
|
||||||
|
|
||||||
// the privilege for the restrictable
|
// the privilege for the restrictable
|
||||||
String privilegeName = restrictable.getPrivilegeName();
|
String privilegeName = restrictable.getPrivilegeName();
|
||||||
IPrivilege privilege = this.privileges.get(privilegeName);
|
Privilege privilege = this.privileges.get(privilegeName);
|
||||||
if (privilege == null) {
|
if (privilege == null) {
|
||||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"),
|
String msg = format(getString("Privilege.accessdenied.noprivilege"), getUsername(), privilegeName,
|
||||||
getUsername(), privilegeName, restrictable.getClass().getName(), restrictable.getPrivilegeValue());
|
restrictable.getClass().getName(), restrictable.getPrivilegeValue());
|
||||||
throw new AccessDeniedException(msg);
|
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
|
* 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
|
* true if the user has the privilege, and false if not
|
||||||
*
|
*
|
||||||
* @param restrictable
|
* @param restrictable the {@link Restrictable} which the user wants to access
|
||||||
* the {@link Restrictable} which the user wants to access
|
|
||||||
*
|
*
|
||||||
* @return returns true if the user has the privilege, and false if not
|
* @return returns true if the user has the privilege, and false if not
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
* errors
|
||||||
*/
|
*/
|
||||||
public boolean hasPrivilege(Restrictable restrictable) throws PrivilegeException {
|
public boolean hasPrivilege(Restrictable restrictable) throws PrivilegeException {
|
||||||
|
|
||||||
// the privilege for the restrictable
|
// the privilege for the restrictable
|
||||||
String privilegeName = restrictable.getPrivilegeName();
|
String privilegeName = restrictable.getPrivilegeName();
|
||||||
IPrivilege privilege = this.privileges.get(privilegeName);
|
Privilege privilege = this.privileges.get(privilegeName);
|
||||||
if (privilege == null)
|
if (privilege == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -229,15 +250,13 @@ public class PrivilegeContext {
|
||||||
*
|
*
|
||||||
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
* <p>This method uses the {@link SimpleRestrictable} to verify access</p>
|
||||||
*
|
*
|
||||||
* @param privilegeName
|
* @param privilegeName the name of the privilege to verify
|
||||||
* the name of the privilege to verify
|
* @param privilegeValue the value
|
||||||
* @param privilegeValue
|
|
||||||
* the value
|
|
||||||
*
|
*
|
||||||
* @return returns true if the user has the privilege, and false if not
|
* @return returns true if the user has the privilege, and false if not
|
||||||
*
|
*
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException if there is an internal error due to wrongly configured privileges or programming
|
||||||
* if there is an internal error due to wrongly configured privileges or programming errors
|
* errors
|
||||||
*/
|
*/
|
||||||
public boolean hasPrivilege(String privilegeName, String privilegeValue) throws PrivilegeException {
|
public boolean hasPrivilege(String privilegeName, String privilegeValue) throws PrivilegeException {
|
||||||
return hasPrivilege(new SimpleRestrictable(privilegeName, privilegeValue));
|
return hasPrivilege(new SimpleRestrictable(privilegeName, privilegeValue));
|
||||||
|
|
|
@ -15,27 +15,25 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.model;
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
import li.strolch.privilege.policy.PrivilegePolicy;
|
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
|
* 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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public class PrivilegeRep implements Serializable {
|
public class PrivilegeRep {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String policy;
|
private String policy;
|
||||||
|
@ -43,48 +41,57 @@ public class PrivilegeRep implements Serializable {
|
||||||
private Set<String> denyList;
|
private Set<String> denyList;
|
||||||
private Set<String> allowList;
|
private Set<String> allowList;
|
||||||
|
|
||||||
|
private boolean readOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name the name of this privilege, which is unique to all privileges known in the
|
||||||
* the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler}
|
* {@link PrivilegeHandler}
|
||||||
* @param policy
|
* @param policy the {@link PrivilegePolicy} configured to evaluate if the privilege is granted
|
||||||
* 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
|
||||||
* @param allAllowed
|
* {@link Restrictable}
|
||||||
* a boolean defining if a {@link Role} with this {@link IPrivilege} has unrestricted access to a {@link
|
* @param denyList a list of deny rules for this {@link Privilege}
|
||||||
* Restrictable}
|
* @param allowList a list of allow rules for this {@link Privilege}
|
||||||
* @param denyList
|
|
||||||
* a list of deny rules for this {@link IPrivilege}
|
|
||||||
* @param allowList
|
|
||||||
* a list of allow rules for this {@link IPrivilege}
|
|
||||||
*/
|
*/
|
||||||
public PrivilegeRep(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
public PrivilegeRep(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
|
||||||
this.name = trimOrEmpty(name);
|
this.name = trimOrEmpty(name);
|
||||||
this.policy = trimOrEmpty(policy);
|
this.policy = trimOrEmpty(policy);
|
||||||
this.allAllowed = allAllowed;
|
this.allAllowed = allAllowed;
|
||||||
this.denyList = denyList;
|
setDenyList(denyList == null ? Set.of() : denyList);
|
||||||
this.allowList = allowList;
|
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
|
* Validates that all required fields are set
|
||||||
*/
|
*/
|
||||||
public void validate() {
|
public void validate() {
|
||||||
|
if (isEmpty(this.name))
|
||||||
if (StringHelper.isEmpty(this.name)) {
|
|
||||||
throw new PrivilegeException("No name defined!");
|
throw new PrivilegeException("No name defined!");
|
||||||
}
|
if (isEmpty(this.policy))
|
||||||
|
throw new PrivilegeException("No policy defined!");
|
||||||
if (StringHelper.isEmpty(this.policy)) {
|
if (this.denyList == null)
|
||||||
throw new PrivilegeException("policy is null!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.denyList == null) {
|
|
||||||
throw new PrivilegeException("denyList is null");
|
throw new PrivilegeException("denyList is null");
|
||||||
}
|
if (this.allowList == null)
|
||||||
if (this.allowList == null) {
|
|
||||||
throw new PrivilegeException("allowList is null");
|
throw new PrivilegeException("allowList is null");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,10 +102,10 @@ public class PrivilegeRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name the name to set
|
||||||
* the name to set
|
|
||||||
*/
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
assertNotReadonly();
|
||||||
this.name = trimOrEmpty(name);
|
this.name = trimOrEmpty(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +117,10 @@ public class PrivilegeRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param policy
|
* @param policy the policy to set
|
||||||
* the policy to set
|
|
||||||
*/
|
*/
|
||||||
public void setPolicy(String policy) {
|
public void setPolicy(String policy) {
|
||||||
|
assertNotReadonly();
|
||||||
this.policy = trimOrEmpty(policy);
|
this.policy = trimOrEmpty(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,10 +132,10 @@ public class PrivilegeRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allAllowed
|
* @param allAllowed the allAllowed to set
|
||||||
* the allAllowed to set
|
|
||||||
*/
|
*/
|
||||||
public void setAllAllowed(boolean allAllowed) {
|
public void setAllAllowed(boolean allAllowed) {
|
||||||
|
assertNotReadonly();
|
||||||
this.allAllowed = allAllowed;
|
this.allAllowed = allAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,30 +143,30 @@ public class PrivilegeRep implements Serializable {
|
||||||
* @return the denyList
|
* @return the denyList
|
||||||
*/
|
*/
|
||||||
public Set<String> getDenyList() {
|
public Set<String> getDenyList() {
|
||||||
return this.denyList == null ? new HashSet<>() : this.denyList;
|
return this.denyList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param denyList
|
* @param denyList the denyList to set
|
||||||
* the denyList to set
|
|
||||||
*/
|
*/
|
||||||
public void setDenyList(Set<String> denyList) {
|
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
|
* @return the allowList
|
||||||
*/
|
*/
|
||||||
public Set<String> getAllowList() {
|
public Set<String> getAllowList() {
|
||||||
return this.allowList == null ? new HashSet<>() : this.allowList;
|
return this.allowList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allowList
|
* @param allowList the allowList to set
|
||||||
* the allowList to set
|
|
||||||
*/
|
*/
|
||||||
public void setAllowList(Set<String> allowList) {
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PrivilegeRep [name=" + this.name + ", policy=" + this.policy + ", allAllowed=" + this.allAllowed
|
return "PrivilegeRep [name=" + this.name + ", policy=" + this.policy + ", allAllowed=" + this.allAllowed +
|
||||||
+ ", denyList=" + (this.denyList == null ? "null" : this.denyList.size()) + ", allowList=" + (
|
", denyList=" + this.denyList.size() + ", allowList=" + this.allowList.size() + "]";
|
||||||
this.allowList == null ?
|
|
||||||
"null" :
|
|
||||||
this.allowList.size()) + "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -193,10 +197,13 @@ public class PrivilegeRep implements Serializable {
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
PrivilegeRep other = (PrivilegeRep) obj;
|
PrivilegeRep other = (PrivilegeRep) obj;
|
||||||
if (this.name == null) {
|
if (this.name == null)
|
||||||
return other.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) {
|
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
||||||
* <p>
|
* <p>
|
||||||
* Objects implementing this interface are used to grant/restrict privileges to them. A {@link PrivilegePolicy}
|
* 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
|
* 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
|
* evaluating access
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
@ -30,9 +30,9 @@ import li.strolch.privilege.policy.PrivilegePolicy;
|
||||||
public interface Restrictable {
|
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();
|
String getPrivilegeName();
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.model;
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
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
|
* 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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public class RoleRep implements Serializable {
|
public class RoleRep {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private List<PrivilegeRep> privileges;
|
private Map<String, PrivilegeRep> privileges;
|
||||||
|
|
||||||
|
private boolean readOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name the name of this role
|
||||||
* the name of this role
|
* @param privileges the list of privileges granted to 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.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
|
* validates that all required fields are set
|
||||||
*/
|
*/
|
||||||
public void validate() {
|
public void validate() {
|
||||||
if (StringHelper.isEmpty(this.name))
|
if (isEmpty(this.name))
|
||||||
throw new PrivilegeException("name is null");
|
throw new PrivilegeException("name is null");
|
||||||
|
|
||||||
if (this.privileges != null && !this.privileges.isEmpty()) {
|
for (PrivilegeRep privilege : this.privileges.values()) {
|
||||||
for (PrivilegeRep privilege : this.privileges) {
|
try {
|
||||||
try {
|
privilege.validate();
|
||||||
privilege.validate();
|
} catch (Exception e) {
|
||||||
} catch (Exception e) {
|
String msg = "Privilege {0} is invalid on role {1}";
|
||||||
String msg = "Privilege {0} is invalid on role {1}";
|
msg = MessageFormat.format(msg, privilege.getName(), this.name);
|
||||||
msg = MessageFormat.format(msg, privilege.getName(), this.name);
|
throw new PrivilegeException(msg, e);
|
||||||
throw new PrivilegeException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,30 +94,29 @@ public class RoleRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name the name to set
|
||||||
* the name to set
|
|
||||||
*/
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
assertNotReadonly();
|
||||||
this.name = trimOrEmpty(name);
|
this.name = trimOrEmpty(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Map<String, PrivilegeRep> getPrivileges() {
|
||||||
* Returns the privileges assigned to this Role as a list
|
if (this.privileges == null)
|
||||||
*
|
return null;
|
||||||
* @return the privileges assigned to this Role as a list
|
return this.privileges;
|
||||||
*/
|
|
||||||
public List<PrivilegeRep> getPrivileges() {
|
|
||||||
return this.privileges == null ? new ArrayList<>() : this.privileges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setPrivileges(Map<String, PrivilegeRep> privileges) {
|
||||||
* Sets the privileges on this from a list
|
assertNotReadonly();
|
||||||
*
|
DBC.PRE.assertNotNull("privileges must not be null!", privileges);
|
||||||
* @param privileges
|
this.privileges = new HashMap<>(privileges);
|
||||||
* the list of privileges to assign to this role
|
}
|
||||||
*/
|
|
||||||
public void setPrivileges(List<PrivilegeRep> privileges) {
|
public void addPrivilege(PrivilegeRep privilegeRep) {
|
||||||
this.privileges = privileges;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RoleRep [name=" + this.name + ", privilegeMap=" + (this.privileges == null ? "null" : this.privileges)
|
return "RoleRep [name=" + this.name + ", privilegeMap=" + this.privileges + "]";
|
||||||
+ "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,10 +146,13 @@ public class RoleRep implements Serializable {
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
RoleRep other = (RoleRep) obj;
|
RoleRep other = (RoleRep) obj;
|
||||||
if (this.name == null) {
|
if (this.name == null)
|
||||||
return other.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) {
|
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
||||||
|
|
|
@ -26,10 +26,8 @@ public class SimpleRestrictable implements Restrictable {
|
||||||
private final Object value;
|
private final Object value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name the name of the privilege
|
||||||
* the name of the privilege
|
* @param value the value allowed on the privilege
|
||||||
* @param value
|
|
||||||
* the value allowed on the privilege
|
|
||||||
*/
|
*/
|
||||||
public SimpleRestrictable(String name, Object value) {
|
public SimpleRestrictable(String name, Object value) {
|
||||||
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
DBC.PRE.assertNotEmpty("name must not be empty", name);
|
||||||
|
|
|
@ -15,20 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.model;
|
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.PrivilegeConstants;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
import li.strolch.privilege.model.internal.UserHistory;
|
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
|
* 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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public class UserRep implements Serializable {
|
public class UserRep {
|
||||||
|
|
||||||
private String userId;
|
private String userId;
|
||||||
private String username;
|
private String username;
|
||||||
|
@ -45,47 +44,40 @@ public class UserRep implements Serializable {
|
||||||
private String lastname;
|
private String lastname;
|
||||||
private UserState userState;
|
private UserState userState;
|
||||||
private Locale locale;
|
private Locale locale;
|
||||||
|
private Set<String> groups;
|
||||||
private Set<String> roles;
|
private Set<String> roles;
|
||||||
private Map<String, String> properties;
|
private Map<String, String> properties;
|
||||||
|
|
||||||
private UserHistory history;
|
private UserHistory history;
|
||||||
|
|
||||||
|
private boolean readOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
*
|
*
|
||||||
* @param userId
|
* @param userId the user's id
|
||||||
* the user's id
|
* @param username the user's login name
|
||||||
* @param username
|
* @param firstname the user's first name
|
||||||
* the user's login name
|
* @param lastname the user's last name
|
||||||
* @param firstname
|
* @param userState the user's {@link UserState}
|
||||||
* the user's first name
|
* @param groups the set of {@link li.strolch.privilege.model.internal.Group}s assigned to this user
|
||||||
* @param lastname
|
* @param roles the set of {@link Role}s assigned to this user
|
||||||
* the user's last name
|
* @param locale the user's {@link Locale}
|
||||||
* @param userState
|
* @param propertyMap a {@link Map} containing string value pairs of properties for this user
|
||||||
* 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 UserRep(String userId, String username, String firstname, String lastname, UserState userState,
|
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.userId = trimOrEmpty(userId);
|
||||||
this.username = trimOrEmpty(username);
|
this.username = trimOrEmpty(username);
|
||||||
this.firstname = trimOrEmpty(firstname);
|
this.firstname = trimOrEmpty(firstname);
|
||||||
this.lastname = trimOrEmpty(lastname);
|
this.lastname = trimOrEmpty(lastname);
|
||||||
this.userState = userState;
|
this.userState = userState;
|
||||||
this.roles = roles == null ? null : roles.stream().map(String::trim).collect(Collectors.toSet());
|
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
|
setGroups(groups == null ? Set.of() : groups);
|
||||||
if (propertyMap != null) {
|
setRoles(roles == null ? Set.of() : roles);
|
||||||
this.properties = new HashMap<>();
|
setProperties(properties == null ? Map.of() : properties);
|
||||||
propertyMap.forEach((key, value) -> this.properties.put(key.trim(), value.trim()));
|
this.history = history == null ? UserHistory.EMPTY : history;
|
||||||
}
|
|
||||||
|
|
||||||
this.history = history;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -97,30 +89,53 @@ public class UserRep implements Serializable {
|
||||||
* Validates that all required fields are set
|
* Validates that all required fields are set
|
||||||
*/
|
*/
|
||||||
public void validate() {
|
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))
|
// username must be at least 3 characters in length
|
||||||
throw new PrivilegeException("userId is null or empty");
|
if (this.username.length() < 3) {
|
||||||
|
String msg = MessageFormat.format("The given username ''{0}'' is shorter than 3 characters", this.username);
|
||||||
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);
|
|
||||||
throw new PrivilegeException(msg);
|
throw new PrivilegeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.userState == null)
|
if (this.userState == null)
|
||||||
throw new PrivilegeException("userState is null");
|
throw new PrivilegeException("userState may not be null");
|
||||||
|
|
||||||
if (StringHelper.isEmpty(this.firstname))
|
if (this.userState != UserState.SYSTEM) {
|
||||||
throw new PrivilegeException("firstname is null or empty");
|
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))
|
if (this.groups == null)
|
||||||
throw new PrivilegeException("lastname is null or empty");
|
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())
|
if (this.groups.isEmpty() && this.roles.isEmpty())
|
||||||
throw new PrivilegeException("roles is null or empty");
|
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() {
|
public boolean isSystemUser() {
|
||||||
|
@ -145,10 +160,10 @@ public class UserRep implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Set the userId
|
* Set the userId
|
||||||
*
|
*
|
||||||
* @param userId
|
* @param userId to set
|
||||||
* to set
|
|
||||||
*/
|
*/
|
||||||
public void setUserId(String userId) {
|
public void setUserId(String userId) {
|
||||||
|
assertNotReadonly();
|
||||||
this.userId = trimOrEmpty(userId);
|
this.userId = trimOrEmpty(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,10 +175,10 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param username
|
* @param username the username to set
|
||||||
* the username to set
|
|
||||||
*/
|
*/
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
|
assertNotReadonly();
|
||||||
this.username = trimOrEmpty(username);
|
this.username = trimOrEmpty(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,10 +190,10 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param firstname
|
* @param firstname the firstname to set
|
||||||
* the firstname to set
|
|
||||||
*/
|
*/
|
||||||
public void setFirstname(String firstname) {
|
public void setFirstname(String firstname) {
|
||||||
|
assertNotReadonly();
|
||||||
this.firstname = trimOrEmpty(firstname);
|
this.firstname = trimOrEmpty(firstname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +205,10 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param lastname
|
* @param lastname the lastname to set
|
||||||
* the lastname to set
|
|
||||||
*/
|
*/
|
||||||
public void setLastname(String lastname) {
|
public void setLastname(String lastname) {
|
||||||
|
assertNotReadonly();
|
||||||
this.lastname = trimOrEmpty(lastname);
|
this.lastname = trimOrEmpty(lastname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,13 +220,27 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param userState
|
* @param userState the userState to set
|
||||||
* the userState to set
|
|
||||||
*/
|
*/
|
||||||
public void setUserState(UserState userState) {
|
public void setUserState(UserState userState) {
|
||||||
|
assertNotReadonly();
|
||||||
this.userState = userState;
|
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
|
* @return the roles
|
||||||
*/
|
*/
|
||||||
|
@ -220,21 +249,19 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param roles
|
* @param roles the roles to set
|
||||||
* the roles to set
|
|
||||||
*/
|
*/
|
||||||
public void setRoles(Set<String> roles) {
|
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) {
|
public boolean hasRole(String role) {
|
||||||
return this.roles.contains(role);
|
return this.roles.contains(role);
|
||||||
}
|
}
|
||||||
|
@ -247,10 +274,10 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param locale
|
* @param locale the locale to set
|
||||||
* the locale to set
|
|
||||||
*/
|
*/
|
||||||
public void setLocale(Locale locale) {
|
public void setLocale(Locale locale) {
|
||||||
|
assertNotReadonly();
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,18 +287,15 @@ public class UserRep implements Serializable {
|
||||||
* @return the user history
|
* @return the user history
|
||||||
*/
|
*/
|
||||||
public UserHistory getHistory() {
|
public UserHistory getHistory() {
|
||||||
if (this.history == null)
|
|
||||||
return new UserHistory();
|
|
||||||
return this.history;
|
return this.history;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the the given property exists
|
* Returns true if the given property exists
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key the property key to check
|
||||||
* 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) {
|
public boolean hasProperty(String key) {
|
||||||
return this.properties.containsKey(key);
|
return this.properties.containsKey(key);
|
||||||
|
@ -280,40 +304,41 @@ public class UserRep implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Returns the property with the given key
|
* Returns the property with the given key
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key the key for which the property is to be returned
|
||||||
* the key for which the property is to be returned
|
|
||||||
*
|
*
|
||||||
* @return the property with the given key, or null if the property is not defined
|
* @return the property with the given key, or null if the property is not defined
|
||||||
*/
|
*/
|
||||||
public String getProperty(String key) {
|
public String getProperty(String key) {
|
||||||
if (this.properties == null)
|
|
||||||
return null;
|
|
||||||
return this.properties.get(key);
|
return this.properties.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the property with the key to the value
|
* Set the property with the key to the value
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key the key of the property to set
|
||||||
* the key of the property to set
|
* @param value the value of the property to set
|
||||||
* @param value
|
|
||||||
* the value of the property to set
|
|
||||||
*/
|
*/
|
||||||
public void setProperty(String key, String value) {
|
public void setProperty(String key, String value) {
|
||||||
if (this.properties == null)
|
DBC.PRE.assertNotEmpty("key must not be empty!", key);
|
||||||
this.properties = new HashMap<>(1);
|
DBC.PRE.assertNotEmpty("value must not be empty!", value);
|
||||||
|
assertNotReadonly();
|
||||||
this.properties.put(key.trim(), value.trim());
|
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
|
* Returns the {@link Set} of keys of all properties
|
||||||
*
|
*
|
||||||
* @return the {@link Set} of keys of all properties
|
* @return the {@link Set} of keys of all properties
|
||||||
*/
|
*/
|
||||||
public Set<String> getPropertyKeySet() {
|
public Set<String> getPropertyKeySet() {
|
||||||
if (this.properties == null)
|
return this.properties.keySet();
|
||||||
return new HashSet<>();
|
|
||||||
return new HashSet<>(this.properties.keySet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,9 +347,7 @@ public class UserRep implements Serializable {
|
||||||
* @return the map of properties
|
* @return the map of properties
|
||||||
*/
|
*/
|
||||||
public Map<String, String> getProperties() {
|
public Map<String, String> getProperties() {
|
||||||
if (this.properties == null)
|
return this.properties;
|
||||||
return new HashMap<>();
|
|
||||||
return new HashMap<>(this.properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -361,9 +384,9 @@ public class UserRep implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "UserRep [userId=" + this.userId + ", username=" + this.username + ", firstname=" + this.firstname
|
return "UserRep [userId=" + this.userId + ", username=" + this.username + ", firstname=" + this.firstname +
|
||||||
+ ", lastname=" + this.lastname + ", userState=" + this.userState + ", locale=" + this.locale
|
", lastname=" + this.lastname + ", userState=" + this.userState + ", locale=" + this.locale +
|
||||||
+ ", roles=" + this.roles + "]";
|
", roles=" + this.roles + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -390,12 +413,8 @@ public class UserRep implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRep getCopy() {
|
public UserRep getCopy() {
|
||||||
|
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, this.groups,
|
||||||
Set<String> roles = new HashSet<>(this.roles);
|
this.roles, this.locale, this.properties, this.history);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T accept(PrivilegeElementVisitor<T> visitor) {
|
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.*;
|
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;
|
@Override
|
||||||
private final byte[] salt;
|
public String toString() {
|
||||||
private final String hashAlgorithm;
|
return buildPasswordString();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PasswordCrypt(byte[] password, byte[] salt, String hashAlgorithm, int hashIterations, int hashKeyLength) {
|
public String buildPasswordString() {
|
||||||
this.password = password;
|
if (this.password == null || this.salt == null || this.hashAlgorithm == null || this.hashIterations == -1 ||
|
||||||
this.salt = salt;
|
this.hashKeyLength == -1) {
|
||||||
this.hashAlgorithm = hashAlgorithm;
|
return null;
|
||||||
this.hashIterations = hashIterations;
|
}
|
||||||
this.hashKeyLength = hashKeyLength;
|
|
||||||
|
return buildPasswordString(this.hashAlgorithm, this.hashIterations, this.hashKeyLength, this.salt,
|
||||||
|
this.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getPassword() {
|
public static String buildPasswordString(String hashAlgorithm, int hashIterations, int hashKeyLength, byte[] salt,
|
||||||
return password;
|
byte[] passwordArr) {
|
||||||
|
String algo = hashAlgorithm + "," + hashIterations + "," + hashKeyLength;
|
||||||
|
String hash = toHexString(salt);
|
||||||
|
String password = toHexString(passwordArr);
|
||||||
|
return "$" + algo + "$" + hash + "$" + password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getSalt() {
|
public static PasswordCrypt of(byte[] password, byte[] salt) {
|
||||||
return salt;
|
return new PasswordCrypt(password, salt, null, -1, -1);
|
||||||
}
|
|
||||||
|
|
||||||
public String getHashAlgorithm() {
|
|
||||||
return hashAlgorithm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHashIterations() {
|
|
||||||
return hashIterations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHashKeyLength() {
|
|
||||||
return hashKeyLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PasswordCrypt parse(String passwordS, String saltS) {
|
public static PasswordCrypt parse(String passwordS, String saltS) {
|
||||||
|
@ -55,14 +40,14 @@ public class PasswordCrypt {
|
||||||
salt = fromHexString(saltS.trim());
|
salt = fromHexString(saltS.trim());
|
||||||
|
|
||||||
if (isEmpty(passwordS))
|
if (isEmpty(passwordS))
|
||||||
return new PasswordCrypt(null, salt);
|
return PasswordCrypt.of(null, salt);
|
||||||
|
|
||||||
passwordS = passwordS.trim();
|
passwordS = passwordS.trim();
|
||||||
|
|
||||||
byte[] password;
|
byte[] password;
|
||||||
if (!passwordS.startsWith("$")) {
|
if (!passwordS.startsWith("$")) {
|
||||||
password = fromHexString(passwordS);
|
password = fromHexString(passwordS);
|
||||||
return new PasswordCrypt(password, salt);
|
return PasswordCrypt.of(password, salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] parts = passwordS.split("\\$");
|
String[] parts = passwordS.split("\\$");
|
||||||
|
@ -86,28 +71,4 @@ public class PasswordCrypt {
|
||||||
|
|
||||||
return new PasswordCrypt(password, salt, hashAlgorithm, hashIterations, hashKeyLength);
|
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;
|
package li.strolch.privilege.model.internal;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
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.PrivilegeRep;
|
||||||
import li.strolch.privilege.model.RoleRep;
|
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>
|
* <p>
|
||||||
|
@ -37,57 +40,32 @@ import li.strolch.utils.helper.StringHelper;
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public final class Role {
|
public record Role(String name, Map<String, Privilege> privilegeMap) {
|
||||||
|
|
||||||
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 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.name = name;
|
||||||
this.privilegeMap = Collections.unmodifiableMap(privilegeMap);
|
this.privilegeMap = Map.copyOf(privilegeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct {@link Role} from its representation {@link RoleRep}
|
* Construct {@link Role} from its representation {@link RoleRep}
|
||||||
*
|
*
|
||||||
* @param roleRep
|
* @param roleRep the representation from which to create the {@link Role}
|
||||||
* the representation from which to create the {@link Role}
|
|
||||||
*/
|
*/
|
||||||
public Role(RoleRep roleRep) {
|
public static Role of(RoleRep roleRep) {
|
||||||
|
|
||||||
String name = roleRep.getName();
|
String name = roleRep.getName();
|
||||||
if (StringHelper.isEmpty(name)) {
|
if (isEmpty(name))
|
||||||
throw new PrivilegeException("No name defined!");
|
throw new PrivilegeException("No name defined!");
|
||||||
}
|
if (roleRep.getPrivileges() == null)
|
||||||
|
|
||||||
if (roleRep.getPrivileges() == null) {
|
|
||||||
throw new PrivilegeException("Privileges may not be null!");
|
throw new PrivilegeException("Privileges may not be null!");
|
||||||
}
|
|
||||||
|
|
||||||
// build privileges from rep
|
// build privileges from rep
|
||||||
Map<String, IPrivilege> privilegeMap = new HashMap<>(roleRep.getPrivileges().size());
|
Map<String, Privilege> privilegeMap = new HashMap<>(roleRep.getPrivileges().size());
|
||||||
for (PrivilegeRep privilege : roleRep.getPrivileges()) {
|
roleRep.getPrivileges().values().forEach(p -> privilegeMap.put(p.getName(), Privilege.of(p)));
|
||||||
privilegeMap.put(privilege.getName(), new PrivilegeImpl(privilege));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.name = name;
|
return new Role(name, privilegeMap);
|
||||||
this.privilegeMap = Collections.unmodifiableMap(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() {
|
public Set<String> getPrivilegeNames() {
|
||||||
return this.privilegeMap.keySet();
|
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);
|
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
|
* @param name the name of the {@link Privilege}
|
||||||
* the name of the {@link IPrivilege}
|
|
||||||
*
|
*
|
||||||
* @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) {
|
public boolean hasPrivilege(String name) {
|
||||||
return this.privilegeMap.containsKey(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
|
* @return a {@link RoleRep} which is a representation of this object used to serialize and view on clients
|
||||||
*/
|
*/
|
||||||
public RoleRep asRoleRep() {
|
public RoleRep asRoleRep() {
|
||||||
List<PrivilegeRep> privileges = new ArrayList<>();
|
Map<String, PrivilegeRep> privileges = new HashMap<>();
|
||||||
for (Entry<String, IPrivilege> entry : this.privilegeMap.entrySet()) {
|
this.privilegeMap.values().forEach(p -> privileges.put(p.getName(), p.asPrivilegeRep()));
|
||||||
privileges.add(entry.getValue().asPrivilegeRep());
|
|
||||||
}
|
|
||||||
return new RoleRep(this.name, privileges);
|
return new RoleRep(this.name, privileges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
package li.strolch.privilege.model.internal;
|
package li.strolch.privilege.model.internal;
|
||||||
|
|
||||||
import li.strolch.privilege.base.PrivilegeConstants;
|
import li.strolch.privilege.base.PrivilegeConstants;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
|
||||||
import li.strolch.privilege.model.UserRep;
|
import li.strolch.privilege.model.UserRep;
|
||||||
import li.strolch.privilege.model.UserState;
|
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.*;
|
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||||
|
|
||||||
|
@ -34,59 +36,36 @@ import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||||
* that
|
* that
|
||||||
* </p>
|
* </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>
|
* @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,
|
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) {
|
boolean passwordChangeRequested, UserHistory history) {
|
||||||
|
|
||||||
if (StringHelper.isEmpty(userId))
|
DBC.PRE.assertNotEmpty("userId must not be empty", userId);
|
||||||
throw new PrivilegeException("No UserId defined!");
|
DBC.PRE.assertNotEmpty("username must not be empty", username);
|
||||||
if (userState == null)
|
DBC.PRE.assertNotNull("userState must not be null", userState);
|
||||||
throw new PrivilegeException("No userState defined!");
|
DBC.PRE.assertNotNull("history must not be null", history);
|
||||||
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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (history == null)
|
if (userState != UserState.SYSTEM) {
|
||||||
throw new PrivilegeException("History must not be null!");
|
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
|
// passwordCrypt may be null, meaning not able to login
|
||||||
// roles may be null, meaning not able to login and must be added later
|
// roles may be null, meaning not able to login and must be added later
|
||||||
|
@ -103,35 +82,19 @@ public final class User {
|
||||||
this.firstname = firstname;
|
this.firstname = firstname;
|
||||||
this.lastname = lastname;
|
this.lastname = lastname;
|
||||||
|
|
||||||
if (roles == null)
|
this.groups = groups == null ? Set.of() : Set.copyOf(groups);
|
||||||
this.roles = Collections.emptySet();
|
this.roles = roles == null ? Set.of() : Set.copyOf(roles);
|
||||||
else
|
this.locale = locale == null ? Locale.getDefault() : locale;
|
||||||
this.roles = Set.copyOf(roles);
|
this.propertyMap = propertyMap == null ? Map.of() : Map.copyOf(propertyMap);
|
||||||
|
|
||||||
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.passwordChangeRequested = passwordChangeRequested;
|
this.passwordChangeRequested = passwordChangeRequested;
|
||||||
this.history = history;
|
this.history = history;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the userId
|
|
||||||
*/
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return this.userId;
|
return this.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the username
|
|
||||||
*/
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return this.username;
|
return this.username;
|
||||||
}
|
}
|
||||||
|
@ -145,48 +108,34 @@ public final class User {
|
||||||
return this.passwordCrypt;
|
return this.passwordCrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the first name
|
|
||||||
*/
|
|
||||||
public String getFirstname() {
|
public String getFirstname() {
|
||||||
return this.firstname;
|
return this.firstname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the last name
|
|
||||||
*/
|
|
||||||
public String getLastname() {
|
public String getLastname() {
|
||||||
return this.lastname;
|
return this.lastname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the userState
|
|
||||||
*/
|
|
||||||
public UserState getUserState() {
|
public UserState getUserState() {
|
||||||
return this.userState;
|
return this.userState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Set<String> getGroups() {
|
||||||
* @return the roles
|
return this.groups;
|
||||||
*/
|
}
|
||||||
|
|
||||||
public Set<String> getRoles() {
|
public Set<String> getRoles() {
|
||||||
return this.roles;
|
return this.roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean hasGroup(String group) {
|
||||||
* Returns true if this user has the specified role
|
return this.groups.contains(group);
|
||||||
*
|
}
|
||||||
* @param role the name of the {@link Role} to check for
|
|
||||||
*
|
|
||||||
* @return true if the this user has the specified role
|
|
||||||
*/
|
|
||||||
public boolean hasRole(String role) {
|
public boolean hasRole(String role) {
|
||||||
return this.roles.contains(role);
|
return this.roles.contains(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the locale
|
|
||||||
*/
|
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
return this.locale;
|
return this.locale;
|
||||||
}
|
}
|
||||||
|
@ -195,11 +144,6 @@ public final class User {
|
||||||
return this.passwordChangeRequested;
|
return this.passwordChangeRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the History object
|
|
||||||
*
|
|
||||||
* @return the History object
|
|
||||||
*/
|
|
||||||
public UserHistory getHistory() {
|
public UserHistory getHistory() {
|
||||||
return this.history;
|
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
|
* @return a {@link UserRep} which is a representation of this object used to serialize and view on clients
|
||||||
*/
|
*/
|
||||||
public UserRep asUserRep() {
|
public UserRep asUserRep() {
|
||||||
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState,
|
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, this.groups,
|
||||||
new HashSet<>(this.roles), this.locale, new HashMap<>(this.propertyMap), this.history.getClone());
|
this.roles, this.locale, new HashMap<>(this.propertyMap), this.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -315,9 +259,13 @@ public final class User {
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
User other = (User) obj;
|
User other = (User) obj;
|
||||||
if (this.userId == null) {
|
if (this.userId == null)
|
||||||
return other.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;
|
package li.strolch.privilege.model.internal;
|
||||||
|
|
||||||
|
import li.strolch.privilege.model.Usage;
|
||||||
|
import li.strolch.utils.dbc.DBC;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import li.strolch.privilege.model.Usage;
|
public final class UserChallenge {
|
||||||
|
|
||||||
public class UserChallenge {
|
|
||||||
private final User user;
|
private final User user;
|
||||||
private final String challenge;
|
private final String challenge;
|
||||||
private final String source;
|
private final String source;
|
||||||
|
@ -13,6 +14,10 @@ public class UserChallenge {
|
||||||
private boolean fulfilled;
|
private boolean fulfilled;
|
||||||
|
|
||||||
public UserChallenge(Usage usage, User user, String challenge, String source) {
|
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.usage = usage;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.challenge = challenge;
|
this.challenge = challenge;
|
||||||
|
|
|
@ -1,32 +1,20 @@
|
||||||
package li.strolch.privilege.model.internal;
|
package li.strolch.privilege.model.internal;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.ZonedDateTime;
|
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;
|
public static final UserHistory EMPTY = new UserHistory(EMPTY_VALUE_ZONED_DATE, EMPTY_VALUE_ZONED_DATE,
|
||||||
private ZonedDateTime lastLogin;
|
EMPTY_VALUE_ZONED_DATE);
|
||||||
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 ZonedDateTime getFirstLogin() {
|
public ZonedDateTime getFirstLogin() {
|
||||||
return this.firstLogin;
|
return this.firstLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFirstLoginEmpty() {
|
public boolean isFirstLoginEmpty() {
|
||||||
return this.firstLogin.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
return this.firstLogin.equals(EMPTY_VALUE_ZONED_DATE);
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstLogin(ZonedDateTime firstLogin) {
|
|
||||||
this.firstLogin = firstLogin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZonedDateTime getLastLogin() {
|
public ZonedDateTime getLastLogin() {
|
||||||
|
@ -34,11 +22,7 @@ public class UserHistory implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLastLoginEmpty() {
|
public boolean isLastLoginEmpty() {
|
||||||
return this.lastLogin.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
return this.lastLogin.equals(EMPTY_VALUE_ZONED_DATE);
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastLogin(ZonedDateTime lastLogin) {
|
|
||||||
this.lastLogin = lastLogin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZonedDateTime getLastPasswordChange() {
|
public ZonedDateTime getLastPasswordChange() {
|
||||||
|
@ -46,22 +30,26 @@ public class UserHistory implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLastPasswordChangeEmpty() {
|
public boolean isLastPasswordChangeEmpty() {
|
||||||
return this.lastPasswordChange.equals(ISO8601.EMPTY_VALUE_ZONED_DATE);
|
return this.lastPasswordChange.equals(EMPTY_VALUE_ZONED_DATE);
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastPasswordChange(ZonedDateTime lastPasswordChange) {
|
|
||||||
this.lastPasswordChange = lastPasswordChange;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return isFirstLoginEmpty() && isLastLoginEmpty() && isLastPasswordChangeEmpty();
|
return isFirstLoginEmpty() && isLastLoginEmpty() && isLastPasswordChangeEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserHistory getClone() {
|
public UserHistory withFirstLogin(ZonedDateTime firstLogin) {
|
||||||
UserHistory clone = new UserHistory();
|
return new UserHistory(firstLogin, this.lastLogin, lastPasswordChange);
|
||||||
clone.firstLogin = this.firstLogin;
|
}
|
||||||
clone.lastLogin = this.lastLogin;
|
|
||||||
clone.lastPasswordChange = this.lastPasswordChange;
|
public UserHistory withLastLogin(ZonedDateTime lastLogin) {
|
||||||
return clone;
|
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.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
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
|
* 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
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
|
|
||||||
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
||||||
|
@ -54,7 +54,7 @@ public class DefaultPrivilege implements PrivilegePolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable) {
|
||||||
|
|
||||||
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
String privilegeValue = validatePrivilegeValue(privilege, restrictable);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public class DefaultPrivilege implements PrivilegePolicy {
|
||||||
return checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue, false);
|
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);
|
PrivilegePolicyHelper.preValidate(privilege, restrictable);
|
||||||
|
|
||||||
// get the value on which the action is to be performed
|
// 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.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
|
@ -26,7 +26,7 @@ import li.strolch.privilege.model.internal.User;
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* {@link PrivilegePolicy} implements logic to determine if a {@link User} which has the given {@link Role} and the
|
* {@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>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -38,29 +38,29 @@ import li.strolch.privilege.model.internal.User;
|
||||||
public interface PrivilegePolicy {
|
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
|
* @param context
|
||||||
* the privilege context
|
* the privilege context
|
||||||
* @param privilege
|
* @param privilege
|
||||||
* the {@link IPrivilege} containing the permissions
|
* the {@link Privilege} containing the permissions
|
||||||
* @param restrictable
|
* @param restrictable
|
||||||
* the {@link Restrictable} to which the user wants access
|
* the {@link Restrictable} to which the user wants access
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException
|
||||||
* if action not allowed
|
* if action not allowed
|
||||||
*/
|
*/
|
||||||
void validateAction(PrivilegeContext context, IPrivilege privilege, Restrictable restrictable)
|
void validateAction(PrivilegeContext context, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException;
|
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}
|
* Restrictable}
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* the privilege context
|
* the privilege context
|
||||||
* @param privilege
|
* @param privilege
|
||||||
* the {@link IPrivilege} containing the permissions
|
* the {@link Privilege} containing the permissions
|
||||||
* @param restrictable
|
* @param restrictable
|
||||||
* the {@link Restrictable} to which the user wants access
|
* the {@link Restrictable} to which the user wants access
|
||||||
*
|
*
|
||||||
|
@ -69,6 +69,6 @@ public interface PrivilegePolicy {
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException
|
||||||
* if something goes wrong with the validate
|
* 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;
|
throws PrivilegeException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.text.MessageFormat;
|
||||||
import li.strolch.privilege.base.AccessDeniedException;
|
import li.strolch.privilege.base.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.utils.helper.StringHelper;
|
import li.strolch.utils.helper.StringHelper;
|
||||||
|
@ -34,7 +34,7 @@ public class PrivilegePolicyHelper {
|
||||||
* Validates the given values and returns the privilege name
|
* Validates the given values and returns the privilege name
|
||||||
*
|
*
|
||||||
* @param privilege
|
* @param privilege
|
||||||
* the {@link IPrivilege}
|
* the {@link Privilege}
|
||||||
* @param restrictable
|
* @param restrictable
|
||||||
* the {@link Restrictable}
|
* the {@link Restrictable}
|
||||||
*
|
*
|
||||||
|
@ -43,7 +43,7 @@ public class PrivilegePolicyHelper {
|
||||||
* @throws PrivilegeException
|
* @throws PrivilegeException
|
||||||
* if something is wrong
|
* 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)
|
if (privilege == null)
|
||||||
throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull"));
|
throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull"));
|
||||||
if (restrictable == null)
|
if (restrictable == null)
|
||||||
|
@ -88,7 +88,7 @@ public class PrivilegePolicyHelper {
|
||||||
* @throws AccessDeniedException
|
* @throws AccessDeniedException
|
||||||
* if access is denied
|
* 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 {
|
String privilegeValue, boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
// first check values not allowed
|
// first check values not allowed
|
||||||
|
@ -102,7 +102,7 @@ public class PrivilegePolicyHelper {
|
||||||
return handleAccessDenied(ctx, privilege, restrictable, privilegeValue, assertHasPrivilege);
|
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) {
|
String privilegeValue, boolean assertHasPrivilege) {
|
||||||
|
|
||||||
if (assertHasPrivilege) {
|
if (assertHasPrivilege) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
|
@ -42,18 +42,18 @@ import li.strolch.utils.dbc.DBC;
|
||||||
public class RoleAccessPrivilege implements PrivilegePolicy {
|
public class RoleAccessPrivilege implements PrivilegePolicy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
validateAction(ctx, privilege, restrictable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
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 {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
String privilegeName = preValidate(privilege, restrictable);
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
|
@ -41,18 +41,18 @@ import li.strolch.utils.dbc.DBC;
|
||||||
public class UserAccessPrivilege implements PrivilegePolicy {
|
public class UserAccessPrivilege implements PrivilegePolicy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
validateAction(ctx, privilege, restrictable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
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 {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
String privilegeName = preValidate(privilege, restrictable);
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
|
@ -43,13 +43,13 @@ import li.strolch.utils.dbc.DBC;
|
||||||
public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege {
|
public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
validateAction(ctx, privilege, restrictable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
return validateAction(ctx, privilege, restrictable, false);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
String privilegeName = preValidate(privilege, restrictable);
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||||
import li.strolch.privilege.model.Certificate;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
|
|
||||||
|
@ -44,18 +44,18 @@ import li.strolch.privilege.model.Restrictable;
|
||||||
public class UsernameFromCertificatePrivilege implements PrivilegePolicy {
|
public class UsernameFromCertificatePrivilege implements PrivilegePolicy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
validateAction(ctx, privilege, restrictable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
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 {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
preValidate(privilege, restrictable);
|
preValidate(privilege, restrictable);
|
||||||
|
|
|
@ -28,7 +28,7 @@ import li.strolch.privilege.base.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.i18n.PrivilegeMessages;
|
import li.strolch.privilege.i18n.PrivilegeMessages;
|
||||||
import li.strolch.privilege.model.Certificate;
|
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.PrivilegeContext;
|
||||||
import li.strolch.privilege.model.Restrictable;
|
import li.strolch.privilege.model.Restrictable;
|
||||||
|
|
||||||
|
@ -48,19 +48,19 @@ import li.strolch.privilege.model.Restrictable;
|
||||||
public class UsernameFromCertificateWithSameOrganisationPrivilege extends UsernameFromCertificatePrivilege {
|
public class UsernameFromCertificateWithSameOrganisationPrivilege extends UsernameFromCertificatePrivilege {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws AccessDeniedException {
|
throws AccessDeniedException {
|
||||||
validateAction(ctx, privilege, restrictable, true);
|
validateAction(ctx, privilege, restrictable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
|
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
return validateAction(ctx, privilege, restrictable, false);
|
return validateAction(ctx, privilege, restrictable, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
|
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
|
||||||
boolean assertHasPrivilege) throws AccessDeniedException {
|
boolean assertHasPrivilege) throws AccessDeniedException {
|
||||||
|
|
||||||
preValidate(privilege, restrictable);
|
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;
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.model.Usage;
|
import li.strolch.privilege.model.Usage;
|
||||||
import li.strolch.utils.dbc.DBC;
|
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.Attributes;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
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>
|
* @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) {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XML_ROOT_CERTIFICATES:
|
case ROOT_CERTIFICATES -> {
|
||||||
break;
|
}
|
||||||
case XML_CERTIFICATE:
|
case CERTIFICATE -> {
|
||||||
|
CertificateStub stub = new CertificateStub();
|
||||||
CertificateStub stub = new CertificateStub();
|
stub.usage = Usage.valueOf(attributes.getValue(ATTR_USAGE).trim());
|
||||||
stub.usage = Usage.valueOf(attributes.getValue(XML_ATTR_USAGE).trim());
|
stub.sessionId = attributes.getValue(ATTR_SESSION_ID).trim();
|
||||||
stub.sessionId = attributes.getValue(XML_ATTR_SESSION_ID).trim();
|
stub.username = attributes.getValue(ATTR_USERNAME).trim();
|
||||||
stub.username = attributes.getValue(XML_ATTR_USERNAME).trim();
|
stub.authToken = attributes.getValue(ATTR_AUTH_TOKEN).trim();
|
||||||
stub.authToken = attributes.getValue(XML_ATTR_AUTH_TOKEN).trim();
|
stub.source = attributes.getValue(ATTR_SOURCE).trim();
|
||||||
stub.source = attributes.getValue(XML_ATTR_SOURCE).trim();
|
stub.locale = Locale.forLanguageTag(attributes.getValue(ATTR_LOCALE).trim());
|
||||||
stub.locale = Locale.forLanguageTag(attributes.getValue(XML_ATTR_LOCALE).trim());
|
stub.loginTime = ISO8601.parseToZdt(attributes.getValue(ATTR_LOGIN_TIME).trim());
|
||||||
stub.loginTime = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LOGIN_TIME).trim());
|
stub.lastAccess = ISO8601.parseToZdt(attributes.getValue(ATTR_LAST_ACCESS).trim());
|
||||||
stub.lastAccess = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LAST_ACCESS).trim());
|
stub.keepAlive = Boolean.parseBoolean(attributes.getValue(ATTR_KEEP_ALIVE).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("sessionId missing on sessions data!", stub.sessionId);
|
DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken);
|
||||||
DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username);
|
if (isEmpty(stub.source))
|
||||||
DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken);
|
stub.source = SOURCE_UNKNOWN;
|
||||||
|
this.stubs.add(stub);
|
||||||
if (isEmpty(stub.source))
|
}
|
||||||
stub.source = SOURCE_UNKNOWN;
|
default -> throw new PrivilegeException("Unhandled tag " + qName);
|
||||||
|
|
||||||
this.stubs.add(stub);
|
|
||||||
break;
|
|
||||||
|
|
||||||
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;
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
// TODO write JavaDoc...
|
|
||||||
public interface ElementParser {
|
public interface ElementParser {
|
||||||
|
|
||||||
void startElement(String uri, String localName, String qName, Attributes attributes);
|
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;
|
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.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import li.strolch.privilege.helper.XmlConstants;
|
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @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 {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XML_CONTAINER -> this.buildersStack.push(new ContainerParser());
|
case CONTAINER -> this.buildersStack.push(new ContainerParser());
|
||||||
case XML_PARAMETERS -> this.buildersStack.push(new ParametersParser());
|
case PARAMETERS -> this.buildersStack.push(new ParametersParser());
|
||||||
case XML_POLICIES -> this.buildersStack.push(new PoliciesParser());
|
case POLICIES -> this.buildersStack.push(new PoliciesParser());
|
||||||
default -> {
|
default -> {
|
||||||
// nothing to do, probably handle on stack
|
// nothing to do, probably handle on stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.buildersStack.isEmpty())
|
if (!this.buildersStack.isEmpty())
|
||||||
|
@ -73,7 +72,7 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
||||||
this.buildersStack.peek().endElement(uri, localName, qName);
|
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||||
|
|
||||||
ElementParser elementParser = switch (qName) {
|
ElementParser elementParser = switch (qName) {
|
||||||
case XML_CONTAINER, XML_PARAMETERS, XML_POLICIES -> this.buildersStack.pop();
|
case CONTAINER, PARAMETERS, POLICIES -> this.buildersStack.pop();
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,38 +88,38 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XML_CONTAINER -> this.currentElement = qName;
|
case CONTAINER -> this.currentElement = qName;
|
||||||
case XML_HANDLER_ENCRYPTION -> {
|
case HANDLER_PRIVILEGE -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setEncryptionHandlerClassName(className);
|
getContainerModel().setPrivilegeHandlerClassName(className);
|
||||||
}
|
}
|
||||||
case XML_HANDLER_PASSWORD_STRENGTH -> {
|
case HANDLER_ENCRYPTION -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setPasswordStrengthHandlerClassName(className);
|
getContainerModel().setEncryptionHandlerClassName(className);
|
||||||
}
|
}
|
||||||
case XML_HANDLER_PERSISTENCE -> {
|
case HANDLER_PASSWORD_STRENGTH -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setPersistenceHandlerClassName(className);
|
getContainerModel().setPasswordStrengthHandlerClassName(className);
|
||||||
}
|
}
|
||||||
case XML_HANDLER_USER_CHALLENGE -> {
|
case HANDLER_PERSISTENCE -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setUserChallengeHandlerClassName(className);
|
getContainerModel().setPersistenceHandlerClassName(className);
|
||||||
}
|
}
|
||||||
case XML_HANDLER_SSO -> {
|
case HANDLER_USER_CHALLENGE -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setSsoHandlerClassName(className);
|
getContainerModel().setUserChallengeHandlerClassName(className);
|
||||||
}
|
}
|
||||||
case XML_HANDLER_PRIVILEGE -> {
|
case HANDLER_SSO -> {
|
||||||
this.currentElement = qName;
|
this.currentElement = qName;
|
||||||
String className = attributes.getValue(XML_ATTR_CLASS).trim();
|
String className = attributes.getValue(ATTR_CLASS).trim();
|
||||||
getContainerModel().setPrivilegeHandlerClassName(className);
|
getContainerModel().setSsoHandlerClassName(className);
|
||||||
}
|
}
|
||||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,20 +128,17 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
||||||
if (!(child instanceof ParametersParser parametersChild))
|
if (!(child instanceof ParametersParser parametersChild))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
final Map<String, String> params = parametersChild.getParameterMap();
|
||||||
switch (this.currentElement) {
|
switch (this.currentElement) {
|
||||||
case XML_CONTAINER -> getContainerModel().setParameterMap(parametersChild.getParameterMap());
|
case CONTAINER -> getContainerModel().setParameterMap(params);
|
||||||
case XML_HANDLER_ENCRYPTION ->
|
case HANDLER_PRIVILEGE -> getContainerModel().setPrivilegeHandlerParameterMap(params);
|
||||||
getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap());
|
case HANDLER_ENCRYPTION -> getContainerModel().setEncryptionHandlerParameterMap(params);
|
||||||
case XML_HANDLER_PASSWORD_STRENGTH ->
|
case HANDLER_PASSWORD_STRENGTH ->
|
||||||
getContainerModel().setPasswordStrengthHandlerParameterMap(parametersChild.getParameterMap());
|
getContainerModel().setPasswordStrengthHandlerParameterMap(params);
|
||||||
case XML_HANDLER_PERSISTENCE ->
|
case HANDLER_PERSISTENCE -> getContainerModel().setPersistenceHandlerParameterMap(params);
|
||||||
getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap());
|
case HANDLER_USER_CHALLENGE -> getContainerModel().setUserChallengeHandlerParameterMap(params);
|
||||||
case XML_HANDLER_USER_CHALLENGE ->
|
case HANDLER_SSO -> getContainerModel().setSsoHandlerParameterMap(params);
|
||||||
getContainerModel().setUserChallengeHandlerParameterMap(parametersChild.getParameterMap());
|
default -> throw new IllegalStateException("Unexpected value: " + this.currentElement);
|
||||||
case XML_HANDLER_SSO -> getContainerModel().setSsoHandlerParameterMap(parametersChild.getParameterMap());
|
|
||||||
case XML_HANDLER_PRIVILEGE ->
|
|
||||||
getContainerModel().setPrivilegeHandlerParameterMap(parametersChild.getParameterMap());
|
|
||||||
default -> throw new IllegalStateException("Unexpected value: " + this.currentElement);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,9 +151,9 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||||
if (qName.equals(XML_PARAMETER)) {
|
if (qName.equals(PARAMETER)) {
|
||||||
String key = attributes.getValue(XML_ATTR_NAME).trim();
|
String key = attributes.getValue(ATTR_NAME).trim();
|
||||||
String value = attributes.getValue(XML_ATTR_VALUE).trim();
|
String value = attributes.getValue(ATTR_VALUE).trim();
|
||||||
this.parameterMap.put(key, value);
|
this.parameterMap.put(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,9 +172,9 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||||
if (qName.equals(XML_POLICY)) {
|
if (qName.equals(POLICY)) {
|
||||||
String policyName = attributes.getValue(XML_ATTR_NAME).trim();
|
String policyName = attributes.getValue(ATTR_NAME).trim();
|
||||||
String policyClassName = attributes.getValue(XML_ATTR_CLASS).trim();
|
String policyClassName = attributes.getValue(ATTR_CLASS).trim();
|
||||||
|
|
||||||
getContainerModel().addPolicy(policyName, policyClassName);
|
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;
|
package li.strolch.privilege.xml;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import li.strolch.privilege.model.Privilege;
|
||||||
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.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
import li.strolch.utils.helper.StringHelper;
|
import li.strolch.utils.helper.StringHelper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -29,6 +24,11 @@ import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
|
@ -51,9 +51,13 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
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());
|
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());
|
this.buildersStack.push(new PropertyParser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +78,9 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
||||||
this.buildersStack.peek().endElement(uri, localName, qName);
|
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||||
|
|
||||||
ElementParser elementParser = null;
|
ElementParser elementParser = null;
|
||||||
if (qName.equals(XmlConstants.XML_ROLE)) {
|
if (qName.equals(ROLE)) {
|
||||||
elementParser = this.buildersStack.pop();
|
elementParser = this.buildersStack.pop();
|
||||||
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
|
} else if (qName.equals(PROPERTIES)) {
|
||||||
elementParser = this.buildersStack.pop();
|
elementParser = this.buildersStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +113,7 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
||||||
private Set<String> denyList;
|
private Set<String> denyList;
|
||||||
private Set<String> allowList;
|
private Set<String> allowList;
|
||||||
|
|
||||||
private Map<String, IPrivilege> privileges;
|
private Map<String, Privilege> privileges;
|
||||||
|
|
||||||
public RoleParser() {
|
public RoleParser() {
|
||||||
init();
|
init();
|
||||||
|
@ -134,20 +138,15 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
||||||
this.text = new StringBuilder();
|
this.text = new StringBuilder();
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XmlConstants.XML_ROLE:
|
case ROLE -> this.roleName = attributes.getValue(ATTR_NAME).trim();
|
||||||
this.roleName = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
case PRIVILEGE -> {
|
||||||
break;
|
this.privilegeName = attributes.getValue(ATTR_NAME).trim();
|
||||||
case XmlConstants.XML_PRIVILEGE:
|
this.privilegePolicy = attributes.getValue(ATTR_POLICY).trim();
|
||||||
this.privilegeName = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
}
|
||||||
this.privilegePolicy = attributes.getValue(XmlConstants.XML_ATTR_POLICY).trim();
|
case ALLOW, DENY, ALL_ALLOWED -> {
|
||||||
break;
|
}
|
||||||
case XmlConstants.XML_ALLOW:
|
|
||||||
case XmlConstants.XML_DENY:
|
|
||||||
case XmlConstants.XML_ALL_ALLOWED:
|
|
||||||
// no-op
|
// 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
|
@Override
|
||||||
public void endElement(String uri, String localName, String qName) {
|
public void endElement(String uri, String localName, String qName) {
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XmlConstants.XML_ALL_ALLOWED ->
|
case ALL_ALLOWED -> this.allAllowed = StringHelper.parseBoolean(getText());
|
||||||
this.allAllowed = StringHelper.parseBoolean(this.text.toString().trim());
|
case ALLOW -> this.allowList.add(getText());
|
||||||
case XmlConstants.XML_ALLOW -> this.allowList.add(this.text.toString().trim());
|
case DENY -> this.denyList.add(getText());
|
||||||
case XmlConstants.XML_DENY -> this.denyList.add(this.text.toString().trim());
|
case PRIVILEGE -> {
|
||||||
case XmlConstants.XML_PRIVILEGE -> {
|
Privilege privilege = new Privilege(this.privilegeName, this.privilegePolicy, this.allAllowed,
|
||||||
IPrivilege privilege = new PrivilegeImpl(this.privilegeName, this.privilegePolicy, this.allAllowed,
|
this.denyList, this.allowList);
|
||||||
this.denyList, this.allowList);
|
this.privileges.put(this.privilegeName, privilege);
|
||||||
this.privileges.put(this.privilegeName, privilege);
|
this.privilegeName = null;
|
||||||
this.privilegeName = null;
|
this.privilegePolicy = null;
|
||||||
this.privilegePolicy = null;
|
this.allAllowed = false;
|
||||||
this.allAllowed = false;
|
this.denyList = new HashSet<>();
|
||||||
this.denyList = new HashSet<>();
|
this.allowList = new HashSet<>();
|
||||||
this.allowList = new HashSet<>();
|
}
|
||||||
}
|
case ROLE -> {
|
||||||
case XmlConstants.XML_ROLE -> {
|
Role role = new Role(this.roleName, this.privileges);
|
||||||
Role role = new Role(this.roleName, this.privileges);
|
roles.put(role.getName(), role);
|
||||||
roles.put(role.getName(), role);
|
logger.info(MessageFormat.format("New Role: {0}", role));
|
||||||
logger.info(MessageFormat.format("New Role: {0}", role));
|
init();
|
||||||
init();
|
}
|
||||||
}
|
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
||||||
default -> throw new IllegalStateException("Unexpected value: " + qName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getText() {
|
||||||
|
return this.text.toString().trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PropertyParser extends ElementParserAdapter {
|
static class PropertyParser extends ElementParserAdapter {
|
||||||
|
@ -194,11 +195,11 @@ public class PrivilegeRolesSaxReader extends DefaultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||||
if (qName.equals(XmlConstants.XML_PROPERTY)) {
|
if (qName.equals(PROPERTY)) {
|
||||||
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME).trim();
|
String key = attributes.getValue(ATTR_NAME).trim();
|
||||||
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE).trim();
|
String value = attributes.getValue(ATTR_VALUE).trim();
|
||||||
this.parameterMap.put(key, value);
|
this.parameterMap.put(key, value);
|
||||||
} else if (!qName.equals(XmlConstants.XML_PROPERTIES)) {
|
} else if (!qName.equals(PROPERTIES)) {
|
||||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
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;
|
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.UserState;
|
||||||
|
import li.strolch.privilege.model.internal.Group;
|
||||||
import li.strolch.privilege.model.internal.PasswordCrypt;
|
import li.strolch.privilege.model.internal.PasswordCrypt;
|
||||||
import li.strolch.privilege.model.internal.User;
|
import li.strolch.privilege.model.internal.User;
|
||||||
import li.strolch.privilege.model.internal.UserHistory;
|
import li.strolch.privilege.model.internal.UserHistory;
|
||||||
import li.strolch.utils.helper.StringHelper;
|
|
||||||
import li.strolch.utils.iso8601.ISO8601;
|
import li.strolch.utils.iso8601.ISO8601;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -32,6 +27,11 @@ import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
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>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
|
@ -58,9 +58,13 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
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());
|
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());
|
this.buildersStack.push(new PropertyParser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +85,9 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
||||||
this.buildersStack.peek().endElement(uri, localName, qName);
|
this.buildersStack.peek().endElement(uri, localName, qName);
|
||||||
|
|
||||||
ElementParser elementParser = null;
|
ElementParser elementParser = null;
|
||||||
if (qName.equals(XML_USER)) {
|
if (qName.equals(USER)) {
|
||||||
elementParser = this.buildersStack.pop();
|
elementParser = this.buildersStack.pop();
|
||||||
} else if (qName.equals(XML_PROPERTIES)) {
|
} else if (qName.equals(PROPERTIES)) {
|
||||||
elementParser = this.buildersStack.pop();
|
elementParser = this.buildersStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,12 +126,14 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
||||||
String lastname;
|
String lastname;
|
||||||
UserState userState;
|
UserState userState;
|
||||||
Locale locale;
|
Locale locale;
|
||||||
|
final Set<String> groups;
|
||||||
final Set<String> userRoles;
|
final Set<String> userRoles;
|
||||||
Map<String, String> parameters;
|
Map<String, String> parameters;
|
||||||
UserHistory history;
|
UserHistory history;
|
||||||
boolean passwordChangeRequested;
|
boolean passwordChangeRequested;
|
||||||
|
|
||||||
public UserParser() {
|
public UserParser() {
|
||||||
|
this.groups = new HashSet<>();
|
||||||
this.userRoles = new HashSet<>();
|
this.userRoles = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,15 +142,15 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
||||||
|
|
||||||
this.text = new StringBuilder();
|
this.text = new StringBuilder();
|
||||||
|
|
||||||
if (qName.equals(XML_USER)) {
|
if (qName.equals(USER)) {
|
||||||
this.userId = attributes.getValue(XML_ATTR_USER_ID).trim();
|
this.userId = attributes.getValue(ATTR_USER_ID).trim();
|
||||||
this.username = attributes.getValue(XML_ATTR_USERNAME).trim();
|
this.username = attributes.getValue(ATTR_USERNAME).trim();
|
||||||
|
|
||||||
String password = attributes.getValue(XML_ATTR_PASSWORD);
|
String password = attributes.getValue(ATTR_PASSWORD);
|
||||||
String salt = attributes.getValue(XML_ATTR_SALT);
|
String salt = attributes.getValue(ATTR_SALT);
|
||||||
this.passwordCrypt = PasswordCrypt.parse(password, salt);
|
this.passwordCrypt = PasswordCrypt.parse(password, salt);
|
||||||
} else if (qName.equals(XML_HISTORY)) {
|
} else if (qName.equals(HISTORY)) {
|
||||||
this.history = new UserHistory();
|
this.history = UserHistory.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,40 +163,45 @@ public class PrivilegeUsersSaxReader extends DefaultHandler {
|
||||||
public void endElement(String uri, String localName, String qName) {
|
public void endElement(String uri, String localName, String qName) {
|
||||||
|
|
||||||
switch (qName) {
|
switch (qName) {
|
||||||
case XML_FIRSTNAME -> this.firstName = this.text.toString().trim();
|
case FIRSTNAME -> this.firstName = getText();
|
||||||
case XML_LASTNAME -> this.lastname = this.text.toString().trim();
|
case LASTNAME -> this.lastname = getText();
|
||||||
case XML_STATE -> this.userState = UserState.valueOf(this.text.toString().trim());
|
case STATE -> this.userState = UserState.valueOf(getText());
|
||||||
case XML_LOCALE -> this.locale = Locale.forLanguageTag(this.text.toString().trim());
|
case LOCALE -> this.locale = Locale.forLanguageTag(getText());
|
||||||
case XML_PASSWORD_CHANGE_REQUESTED ->
|
case PASSWORD_CHANGE_REQUESTED -> this.passwordChangeRequested = Boolean.parseBoolean(getText());
|
||||||
this.passwordChangeRequested = Boolean.parseBoolean(this.text.toString().trim());
|
case FIRST_LOGIN -> this.history = this.history.withFirstLogin(ISO8601.parseToZdt(getText()));
|
||||||
case XML_FIRST_LOGIN -> this.history.setFirstLogin(ISO8601.parseToZdt(this.text.toString().trim()));
|
case LAST_LOGIN -> this.history = this.history.withLastLogin(ISO8601.parseToZdt(getText()));
|
||||||
case XML_LAST_LOGIN -> this.history.setLastLogin(ISO8601.parseToZdt(this.text.toString().trim()));
|
case LAST_PASSWORD_CHANGE ->
|
||||||
case XML_LAST_PASSWORD_CHANGE ->
|
this.history = this.history.withLastPasswordChange(ISO8601.parseToZdt(getText()));
|
||||||
this.history.setLastPasswordChange(ISO8601.parseToZdt(this.text.toString().trim()));
|
case GROUP -> this.groups.add(getText());
|
||||||
case XML_ROLE -> this.userRoles.add(this.text.toString().trim());
|
case ROLE -> this.userRoles.add(getText());
|
||||||
case XML_USER -> {
|
case USER -> {
|
||||||
if (this.history == null)
|
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,
|
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.userState, this.groups, this.userRoles, this.locale, this.parameters,
|
||||||
this.history);
|
this.passwordChangeRequested, this.history);
|
||||||
|
|
||||||
logger.info(MessageFormat.format("New User: {0}", user));
|
logger.info(MessageFormat.format("New User: {0}", user));
|
||||||
String username = caseInsensitiveUsername ? user.getUsername().toLowerCase() : user.getUsername();
|
String username = caseInsensitiveUsername ? user.getUsername().toLowerCase() : user.getUsername();
|
||||||
users.put(username, user);
|
users.put(username, user);
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
if (!(qName.equals(XML_ROLES) //
|
if (!(qName.equals(ROLES) //
|
||||||
|| qName.equals(XML_PARAMETER) //
|
|| qName.equals(GROUPS) //
|
||||||
|| qName.equals(XML_HISTORY) //
|
|| qName.equals(PARAMETER) //
|
||||||
|| qName.equals(XML_PARAMETERS))) {
|
|| qName.equals(HISTORY) //
|
||||||
|
|| qName.equals(PARAMETERS))) {
|
||||||
throw new IllegalArgumentException("Unhandled tag " + qName);
|
throw new IllegalArgumentException("Unhandled tag " + qName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getText() {
|
||||||
|
return this.text.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyChild(ElementParser child) {
|
public void notifyChild(ElementParser child) {
|
||||||
if (child instanceof PropertyParser) {
|
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.privilegeNull=Privilege may not be null\!
|
||||||
Privilege.restrictableNull=Restrictable may not be null\!
|
Privilege.restrictableNull=Restrictable may not be null\!
|
||||||
Privilege.noprivilege=No Privilege exists with name {0}
|
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.role=User {0} does not have the role {1}
|
||||||
Privilege.noprivilege.user=User {0} does not have the privilege {1}
|
Privilege.noprivilege.user=User {0} does not have the privilege {1}
|
||||||
Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
|
Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
package li.strolch.privilege.test;
|
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.base.PrivilegeException;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||||
import li.strolch.privilege.helper.PrivilegeInitializer;
|
import li.strolch.privilege.helper.PrivilegeInitializer;
|
||||||
|
@ -18,6 +11,13 @@ import org.junit.BeforeClass;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 {
|
public class AbstractPrivilegeTest {
|
||||||
|
|
||||||
protected static final Logger logger = LoggerFactory.getLogger(AbstractPrivilegeTest.class);
|
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) {
|
String rolesFilename) {
|
||||||
try {
|
try {
|
||||||
File configPath = new File("src/test/resources/config");
|
File configPath = new File("src/test/resources/config");
|
||||||
|
|
||||||
File privilegeConfigFile = new File(configPath, configFilename);
|
File privilegeConfigFile = new File(configPath, configFilename);
|
||||||
File privilegeUsersFile = new File(configPath, usersFilename);
|
File privilegeUsersFile = new File(configPath, usersFilename);
|
||||||
|
File privilegeGroupsFile = new File(configPath, groupsFilename);
|
||||||
File privilegeRolesFile = new File(configPath, rolesFilename);
|
File privilegeRolesFile = new File(configPath, rolesFilename);
|
||||||
|
|
||||||
File targetPath = new File("target/" + dst);
|
File targetPath = new File("target/" + dst);
|
||||||
|
@ -72,6 +73,7 @@ public class AbstractPrivilegeTest {
|
||||||
|
|
||||||
File dstConfig = new File(targetPath, configFilename);
|
File dstConfig = new File(targetPath, configFilename);
|
||||||
File dstUsers = new File(targetPath, usersFilename);
|
File dstUsers = new File(targetPath, usersFilename);
|
||||||
|
File dstGroups = new File(targetPath, groupsFilename);
|
||||||
File dstRoles = new File(targetPath, rolesFilename);
|
File dstRoles = new File(targetPath, rolesFilename);
|
||||||
|
|
||||||
// write config
|
// write config
|
||||||
|
@ -81,6 +83,7 @@ public class AbstractPrivilegeTest {
|
||||||
|
|
||||||
// copy model
|
// copy model
|
||||||
Files.copy(privilegeUsersFile.toPath(), dstUsers.toPath());
|
Files.copy(privilegeUsersFile.toPath(), dstUsers.toPath());
|
||||||
|
Files.copy(privilegeGroupsFile.toPath(), dstGroups.toPath());
|
||||||
Files.copy(privilegeRolesFile.toPath(), dstRoles.toPath());
|
Files.copy(privilegeRolesFile.toPath(), dstRoles.toPath());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -20,9 +20,9 @@ public class CryptTest {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
Map<String, String> parameterMap = new HashMap<>();
|
Map<String, String> parameterMap = new HashMap<>();
|
||||||
parameterMap.put(XML_PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
parameterMap.put(PARAM_HASH_ALGORITHM, DEFAULT_ALGORITHM);
|
||||||
parameterMap.put(XML_PARAM_HASH_ITERATIONS, "" + DEFAULT_SMALL_ITERATIONS);
|
parameterMap.put(PARAM_HASH_ITERATIONS, "" + DEFAULT_SMALL_ITERATIONS);
|
||||||
parameterMap.put(XML_PARAM_HASH_KEY_LENGTH, "" + DEFAULT_KEY_LENGTH);
|
parameterMap.put(PARAM_HASH_KEY_LENGTH, "" + DEFAULT_KEY_LENGTH);
|
||||||
|
|
||||||
encryptionHandler = new DefaultEncryptionHandler();
|
encryptionHandler = new DefaultEncryptionHandler();
|
||||||
encryptionHandler.initialize(parameterMap);
|
encryptionHandler.initialize(parameterMap);
|
||||||
|
@ -41,7 +41,7 @@ public class CryptTest {
|
||||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, salt, "PBKDF2WithHmacSHA512", 100000,
|
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, salt, "PBKDF2WithHmacSHA512", 100000,
|
||||||
256);
|
256);
|
||||||
|
|
||||||
assertArrayEquals(passwordCrypt.getPassword(), parsedCryptHash.getPassword());
|
assertArrayEquals(passwordCrypt.password(), parsedCryptHash.password());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -53,9 +53,9 @@ public class CryptTest {
|
||||||
assertNotNull(parsedCryptHash);
|
assertNotNull(parsedCryptHash);
|
||||||
|
|
||||||
char[] password = "admin".toCharArray();
|
char[] password = "admin".toCharArray();
|
||||||
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, parsedCryptHash.getSalt(),
|
PasswordCrypt passwordCrypt = encryptionHandler.hashPassword(password, parsedCryptHash.salt(),
|
||||||
"PBKDF2WithHmacSHA512", 100000, 256);
|
"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() {
|
public static void init() {
|
||||||
removeConfigs(PersistSessionsTest.class.getSimpleName());
|
removeConfigs(PersistSessionsTest.class.getSimpleName());
|
||||||
prepareConfigs(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
prepareConfigs(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||||
"PrivilegeRoles.xml");
|
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -15,14 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.test;
|
package li.strolch.privilege.test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import li.strolch.privilege.model.Privilege;
|
||||||
|
|
||||||
import li.strolch.privilege.model.IPrivilege;
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
|
@ -32,7 +34,7 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
||||||
public static void init() {
|
public static void init() {
|
||||||
removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName());
|
removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName());
|
||||||
prepareConfigs(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml",
|
prepareConfigs(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml",
|
||||||
"PrivilegeUsersMerge.xml", "PrivilegeRolesMerge.xml");
|
"PrivilegeUsersMerge.xml", "PrivilegeGroupsMerge.xml", "PrivilegeRolesMerge.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
@ -49,7 +51,16 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
||||||
public void shouldMergePrivileges1() {
|
public void shouldMergePrivileges1() {
|
||||||
try {
|
try {
|
||||||
login("userA", "admin".toCharArray());
|
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.isAllAllowed());
|
||||||
assertTrue(privilege.getAllowList().isEmpty());
|
assertTrue(privilege.getAllowList().isEmpty());
|
||||||
assertTrue(privilege.getDenyList().isEmpty());
|
assertTrue(privilege.getDenyList().isEmpty());
|
||||||
|
@ -63,7 +74,16 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
||||||
public void shouldMergePrivileges2() {
|
public void shouldMergePrivileges2() {
|
||||||
try {
|
try {
|
||||||
login("userB", "admin".toCharArray());
|
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());
|
assertFalse(privilege.isAllAllowed());
|
||||||
assertEquals(2, privilege.getAllowList().size());
|
assertEquals(2, privilege.getAllowList().size());
|
||||||
assertEquals(2, privilege.getDenyList().size());
|
assertEquals(2, privilege.getDenyList().size());
|
||||||
|
@ -71,4 +91,53 @@ public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
|
||||||
logout();
|
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;
|
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.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.InvalidCredentialsException;
|
import li.strolch.privilege.base.InvalidCredentialsException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
|
@ -41,9 +35,15 @@ import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 />
|
* 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
|
* TODO add more tests, especially with deny and allow lists
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -77,12 +77,12 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
public static void init() {
|
public static void init() {
|
||||||
removeConfigs(PrivilegeTest.class.getSimpleName());
|
removeConfigs(PrivilegeTest.class.getSimpleName());
|
||||||
prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||||
"PrivilegeRoles.xml");
|
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void destroy() {
|
public static void destroy() {
|
||||||
removeConfigs(PrivilegeTest.class.getSimpleName());
|
//removeConfigs(PrivilegeTest.class.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -137,7 +137,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
try {
|
try {
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
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();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addRole(certificate, roleRep);
|
this.privilegeHandler.addRole(certificate, roleRep);
|
||||||
|
@ -209,7 +209,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
MatcherAssert.assertThat(exception.getMessage(), containsString(
|
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("The", user.getFirstname());
|
||||||
assertNotEquals("Admin", user.getLastname());
|
assertNotEquals("Admin", user.getLastname());
|
||||||
|
|
||||||
// let's add a new user bob
|
// set new name
|
||||||
UserRep userRep = new UserRep(null, ADMIN, "The", "Admin", null, null, null, null, null);
|
user.setFirstname("The");
|
||||||
this.privilegeHandler.updateUser(certificate, userRep);
|
user.setLastname("Admin");
|
||||||
|
|
||||||
|
// update user
|
||||||
|
this.privilegeHandler.updateUser(certificate, user, null);
|
||||||
|
|
||||||
user = this.privilegeHandler.getUser(certificate, ADMIN);
|
user = this.privilegeHandler.getUser(certificate, ADMIN);
|
||||||
assertEquals("The", user.getFirstname());
|
assertEquals("The", user.getFirstname());
|
||||||
|
@ -273,8 +278,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
|
|
||||||
// let's add a new user bob
|
// let's add a new user bob
|
||||||
UserRep userRep = new UserRep(null, BOB, null, null, null, null, null, null, null);
|
UserRep userRep = new UserRep(BOB, BOB, "Bob", "Anderson", UserState.ENABLED,
|
||||||
this.privilegeHandler.updateUser(certificate, userRep);
|
Set.of("AppUserLocationA"), null, null, null, null);
|
||||||
|
this.privilegeHandler.updateUser(certificate, userRep, null);
|
||||||
} finally {
|
} finally {
|
||||||
logout();
|
logout();
|
||||||
}
|
}
|
||||||
|
@ -282,25 +288,6 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
MatcherAssert.assertThat(exception.getMessage(), containsString("User bob does not exist"));
|
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
|
@Test
|
||||||
public void shouldQueryUsers() {
|
public void shouldQueryUsers() {
|
||||||
try {
|
try {
|
||||||
|
@ -308,7 +295,24 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
|
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
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);
|
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||||
assertEquals(1, users.size());
|
assertEquals(1, users.size());
|
||||||
assertEquals(ADMIN, users.get(0).getUsername());
|
assertEquals(ADMIN, users.get(0).getUsername());
|
||||||
|
@ -325,8 +329,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
|
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
|
|
||||||
UserRep selectorRep = new UserRep(null, null, null, null, null,
|
UserRep selectorRep = new UserRep(null, null, null, null, null, null, Set.of("PrivilegeAdmin"), null, null,
|
||||||
new HashSet<>(Collections.singletonList("PrivilegeAdmin")), null, null, null);
|
null);
|
||||||
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||||
assertEquals(2, users.size());
|
assertEquals(2, users.size());
|
||||||
assertEquals(ADMIN, users.get(0).getUsername());
|
assertEquals(ADMIN, users.get(0).getUsername());
|
||||||
|
@ -344,7 +348,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
|
|
||||||
UserRep selectorRep = new UserRep(null, null, null, null, null,
|
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);
|
List<UserRep> users = this.privilegeHandler.queryUsers(certificate, selectorRep);
|
||||||
assertEquals(0, users.size());
|
assertEquals(0, users.size());
|
||||||
|
|
||||||
|
@ -360,8 +364,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege",
|
PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege",
|
||||||
true, Collections.emptySet(), Collections.emptySet());
|
true, Set.of(), Set.of());
|
||||||
this.privilegeHandler.addOrReplacePrivilegeOnRole(certificate, ROLE_APP_USER, privilegeRep);
|
RoleRep role = this.privilegeHandler.getRole(certificate, ROLE_APP_USER);
|
||||||
|
role.addPrivilege(privilegeRep);
|
||||||
|
this.privilegeHandler.replaceRole(certificate, role);
|
||||||
} finally {
|
} finally {
|
||||||
logout();
|
logout();
|
||||||
}
|
}
|
||||||
|
@ -375,8 +381,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
try {
|
try {
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY);
|
UserRep user = this.privilegeHandler.getUser(certificate, ADMIN);
|
||||||
this.privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY2);
|
user.addRole(ROLE_MY);
|
||||||
|
user.addRole(ROLE_MY2);
|
||||||
|
this.privilegeHandler.updateUser(certificate, user, null);
|
||||||
} finally {
|
} finally {
|
||||||
logout();
|
logout();
|
||||||
}
|
}
|
||||||
|
@ -540,15 +548,21 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
|
|
||||||
PrivilegeRep passwordRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD,
|
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,
|
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();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addRole(certificate, roleRep);
|
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);
|
logger.info("Added " + ROLE_CHANGE_PW + " to " + TED);
|
||||||
this.privilegeHandler.persist(certificate);
|
this.privilegeHandler.persist(certificate);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -574,7 +588,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
// testAddAppRoleToBob
|
// testAddAppRoleToBob
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
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);
|
logger.info("Added " + ROLE_APP_USER + " to " + BOB);
|
||||||
this.privilegeHandler.persist(certificate);
|
this.privilegeHandler.persist(certificate);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -593,7 +609,10 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
this.ctx.validateAction(restrictable);
|
this.ctx.validateAction(restrictable);
|
||||||
fail("Should fail as bob does not have role app");
|
fail("Should fail as bob does not have role app");
|
||||||
} catch (AccessDeniedException e) {
|
} 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());
|
assertEquals(msg, e.getLocalizedMessage());
|
||||||
} finally {
|
} finally {
|
||||||
logout();
|
logout();
|
||||||
|
@ -656,7 +675,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
// let's add a new user ted
|
// let's add a new user ted
|
||||||
HashSet<String> roles = new HashSet<>();
|
HashSet<String> roles = new HashSet<>();
|
||||||
roles.add(ROLE_USER);
|
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();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||||
logger.info("Added user " + TED);
|
logger.info("Added user " + TED);
|
||||||
|
@ -671,7 +691,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
// testAddAdminRoleToBob
|
// testAddAdminRoleToBob
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
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);
|
logger.info("Added " + ROLE_PRIVILEGE_ADMIN + " to " + ADMIN);
|
||||||
this.privilegeHandler.persist(certificate);
|
this.privilegeHandler.persist(certificate);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -688,14 +710,14 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
// auth as Bob
|
// auth as Bob
|
||||||
login(BOB, ArraysHelper.copyOf(PASS_BOB));
|
login(BOB, ArraysHelper.copyOf(PASS_BOB));
|
||||||
// let's add a new user Ted
|
// 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);
|
new HashMap<>(), null);
|
||||||
certificate = this.ctx.getCertificate();
|
certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||||
fail("User bob may not add a user as bob does not have admin rights!");
|
fail("User bob may not add a user as bob does not have admin rights!");
|
||||||
} catch (PrivilegeException e) {
|
} catch (PrivilegeException e) {
|
||||||
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"),
|
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), BOB,
|
||||||
BOB, PrivilegeHandler.PRIVILEGE_ADD_USER);
|
PrivilegeHandler.PRIVILEGE_ADD_USER);
|
||||||
assertEquals(msg, e.getMessage());
|
assertEquals(msg, e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
logout();
|
logout();
|
||||||
|
@ -716,7 +738,9 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
// testAddRoleUserToBob
|
// testAddRoleUserToBob
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
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);
|
this.privilegeHandler.persist(certificate);
|
||||||
logout();
|
logout();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -728,7 +752,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
try {
|
try {
|
||||||
// add role user
|
// add role user
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
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();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addRole(certificate, roleRep);
|
this.privilegeHandler.addRole(certificate, roleRep);
|
||||||
this.privilegeHandler.persist(certificate);
|
this.privilegeHandler.persist(certificate);
|
||||||
|
@ -768,8 +792,8 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
||||||
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||||
|
|
||||||
// let's add a new user bob
|
// let's add a new user bob
|
||||||
UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW,
|
UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW, Set.of(), Set.of(ROLE_MY), null,
|
||||||
new HashSet<>(Collections.singletonList(ROLE_MY)), null, new HashMap<>(), null);
|
new HashMap<>(), null);
|
||||||
Certificate certificate = this.ctx.getCertificate();
|
Certificate certificate = this.ctx.getCertificate();
|
||||||
this.privilegeHandler.addUser(certificate, userRep, null);
|
this.privilegeHandler.addUser(certificate, userRep, null);
|
||||||
logger.info("Added user " + BOB);
|
logger.info("Added user " + BOB);
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class SsoHandlerTest extends AbstractPrivilegeTest {
|
||||||
public static void init() {
|
public static void init() {
|
||||||
removeConfigs(SsoHandlerTest.class.getSimpleName());
|
removeConfigs(SsoHandlerTest.class.getSimpleName());
|
||||||
prepareConfigs(SsoHandlerTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
prepareConfigs(SsoHandlerTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
|
||||||
"PrivilegeRoles.xml");
|
"PrivilegeGroups.xml", "PrivilegeRoles.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
@ -39,6 +39,7 @@ public class SsoHandlerTest extends AbstractPrivilegeTest {
|
||||||
data.put("username", "admin");
|
data.put("username", "admin");
|
||||||
data.put("firstName", "Admin");
|
data.put("firstName", "Admin");
|
||||||
data.put("lastName", "Istrator");
|
data.put("lastName", "Istrator");
|
||||||
|
data.put("groups", "AppUserLocationA");
|
||||||
data.put("roles", "PrivilegeAdmin, AppUser");
|
data.put("roles", "PrivilegeAdmin, AppUser");
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
|
|
|
@ -4,14 +4,17 @@ import static li.strolch.privilege.test.XmlTest.SRC_TEST;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import li.strolch.privilege.helper.WriteRolesFileHelper;
|
import li.strolch.privilege.helper.WriteRolesFileHelper;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
|
||||||
public class WriteRolesFileHelperTest {
|
public class WriteRolesFileHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldReadAndWriteRolesFile() {
|
public void shouldReadAndWriteRolesFile() throws XMLStreamException, IOException {
|
||||||
|
|
||||||
String src = SRC_TEST + "PrivilegeRoles.xml";
|
String src = SRC_TEST + "PrivilegeRoles.xml";
|
||||||
String dst = "target/WriteRolesFileHelperTest_roles.xml";
|
String dst = "target/WriteRolesFileHelperTest_roles.xml";
|
||||||
|
@ -19,7 +22,7 @@ public class WriteRolesFileHelperTest {
|
||||||
if (new File(dst).exists() && !new File(dst).delete())
|
if (new File(dst).exists() && !new File(dst).delete())
|
||||||
throw new IllegalStateException("Could not delete file " + dst);
|
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());
|
assertTrue(new File(dst).exists());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.privilege.test;
|
package li.strolch.privilege.test;
|
||||||
|
|
||||||
import li.strolch.privilege.handler.DefaultEncryptionHandler;
|
import li.strolch.privilege.handler.*;
|
||||||
import li.strolch.privilege.handler.MailUserChallengeHandler;
|
import li.strolch.privilege.model.Privilege;
|
||||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
|
||||||
import li.strolch.privilege.handler.XmlPersistenceHandler;
|
|
||||||
import li.strolch.privilege.model.IPrivilege;
|
|
||||||
import li.strolch.privilege.model.UserState;
|
import li.strolch.privilege.model.UserState;
|
||||||
import li.strolch.privilege.model.internal.*;
|
import li.strolch.privilege.model.internal.*;
|
||||||
import li.strolch.privilege.test.model.DummySsoHandler;
|
import li.strolch.privilege.test.model.DummySsoHandler;
|
||||||
|
@ -33,7 +30,10 @@ import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
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());
|
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");
|
tmpFile = new File(TARGET_TEST + "PrivilegeRolesTest.xml");
|
||||||
if (tmpFile.exists() && !tmpFile.delete()) {
|
if (tmpFile.exists() && !tmpFile.delete()) {
|
||||||
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
|
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
|
||||||
|
@ -115,7 +120,7 @@ public class XmlTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canWriteConfig() {
|
public void canWriteConfig() throws XMLStreamException, IOException {
|
||||||
|
|
||||||
Map<String, String> parameterMap = new HashMap<>();
|
Map<String, String> parameterMap = new HashMap<>();
|
||||||
Map<String, String> encryptionHandlerParameterMap = new HashMap<>();
|
Map<String, String> encryptionHandlerParameterMap = new HashMap<>();
|
||||||
|
@ -128,6 +133,7 @@ public class XmlTest {
|
||||||
|
|
||||||
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
|
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
|
||||||
containerModel.setParameterMap(parameterMap);
|
containerModel.setParameterMap(parameterMap);
|
||||||
|
containerModel.setPrivilegeHandlerClassName(DefaultPrivilegeHandler.class.getName());
|
||||||
containerModel.setEncryptionHandlerClassName(DefaultEncryptionHandler.class.getName());
|
containerModel.setEncryptionHandlerClassName(DefaultEncryptionHandler.class.getName());
|
||||||
containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap);
|
containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap);
|
||||||
containerModel.setPersistenceHandlerClassName(XmlPersistenceHandler.class.getName());
|
containerModel.setPersistenceHandlerClassName(XmlPersistenceHandler.class.getName());
|
||||||
|
@ -138,11 +144,38 @@ public class XmlTest {
|
||||||
containerModel.addPolicy("DefaultPrivilege", "li.strolch.privilege.policy.DefaultPrivilege");
|
containerModel.addPolicy("DefaultPrivilege", "li.strolch.privilege.policy.DefaultPrivilege");
|
||||||
|
|
||||||
File configFile = new File(TARGET_TEST + "PrivilegeTest.xml");
|
File configFile = new File(TARGET_TEST + "PrivilegeTest.xml");
|
||||||
PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile);
|
PrivilegeConfigSaxWriter configSaxWriter = new PrivilegeConfigSaxWriter(containerModel, configFile);
|
||||||
configSaxWriter.write();
|
configSaxWriter.write();
|
||||||
|
|
||||||
String fileHash = StringHelper.toHexString(FileHelper.hashFileSha256(configFile));
|
String expected = """
|
||||||
assertEquals("dcb6b3ed7198e0a7c88bf5c61c0bd6f0d684415f2a2f29429879edc6bc795f06", fileHash);
|
<?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
|
@Test
|
||||||
|
@ -166,12 +199,13 @@ public class XmlTest {
|
||||||
assertEquals("1", admin.getUserId());
|
assertEquals("1", admin.getUserId());
|
||||||
assertEquals("admin", admin.getUsername());
|
assertEquals("admin", admin.getUsername());
|
||||||
assertEquals("cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344",
|
assertEquals("cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344",
|
||||||
StringHelper.toHexString(admin.getPasswordCrypt().getPassword()));
|
StringHelper.toHexString(admin.getPasswordCrypt().password()));
|
||||||
assertEquals("61646d696e", StringHelper.toHexString(admin.getPasswordCrypt().getSalt()));
|
assertEquals("61646d696e", StringHelper.toHexString(admin.getPasswordCrypt().salt()));
|
||||||
assertEquals("Application", admin.getFirstname());
|
assertEquals("Application", admin.getFirstname());
|
||||||
assertEquals("Administrator", admin.getLastname());
|
assertEquals("Administrator", admin.getLastname());
|
||||||
assertEquals(UserState.ENABLED, admin.getUserState());
|
assertEquals(UserState.ENABLED, admin.getUserState());
|
||||||
assertEquals("en-GB", admin.getLocale().toLanguageTag());
|
assertEquals("en-GB", admin.getLocale().toLanguageTag());
|
||||||
|
assertEquals(Set.of("GroupA"), admin.getGroups());
|
||||||
MatcherAssert.assertThat(admin.getRoles(), containsInAnyOrder("PrivilegeAdmin", "AppUser"));
|
MatcherAssert.assertThat(admin.getRoles(), containsInAnyOrder("PrivilegeAdmin", "AppUser"));
|
||||||
Map<String, String> properties = admin.getProperties();
|
Map<String, String> properties = admin.getProperties();
|
||||||
assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet());
|
assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet());
|
||||||
|
@ -187,8 +221,54 @@ public class XmlTest {
|
||||||
assertEquals("Administrator", systemAdmin.getLastname());
|
assertEquals("Administrator", systemAdmin.getLastname());
|
||||||
assertEquals(UserState.SYSTEM, systemAdmin.getUserState());
|
assertEquals(UserState.SYSTEM, systemAdmin.getUserState());
|
||||||
assertEquals("en-GB", systemAdmin.getLocale().toLanguageTag());
|
assertEquals("en-GB", systemAdmin.getLocale().toLanguageTag());
|
||||||
|
assertEquals(Set.of(), systemAdmin.getGroups());
|
||||||
MatcherAssert.assertThat(systemAdmin.getRoles(), containsInAnyOrder("system_admin_privileges"));
|
MatcherAssert.assertThat(systemAdmin.getRoles(), containsInAnyOrder("system_admin_privileges"));
|
||||||
assertTrue(systemAdmin.getProperties().isEmpty());
|
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
|
@Test
|
||||||
|
@ -212,23 +292,22 @@ public class XmlTest {
|
||||||
// PrivilegeAdmin
|
// PrivilegeAdmin
|
||||||
Role privilegeAdmin = findRole("PrivilegeAdmin", roles);
|
Role privilegeAdmin = findRole("PrivilegeAdmin", roles);
|
||||||
assertEquals("PrivilegeAdmin", privilegeAdmin.getName());
|
assertEquals("PrivilegeAdmin", privilegeAdmin.getName());
|
||||||
assertEquals(18, privilegeAdmin.getPrivilegeNames().size());
|
assertEquals(16, privilegeAdmin.getPrivilegeNames().size());
|
||||||
IPrivilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION);
|
Privilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION);
|
||||||
assertFalse(privilegeAction.isAllAllowed());
|
assertFalse(privilegeAction.isAllAllowed());
|
||||||
assertEquals(5, privilegeAction.getAllowList().size());
|
assertEquals(5, privilegeAction.getAllowList().size());
|
||||||
assertEquals(0, privilegeAction.getDenyList().size());
|
assertEquals(0, privilegeAction.getDenyList().size());
|
||||||
assertEquals("DefaultPrivilege", privilegeAction.getPolicy());
|
assertEquals("DefaultPrivilege", privilegeAction.getPolicy());
|
||||||
|
|
||||||
IPrivilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE);
|
Privilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE);
|
||||||
assertTrue(privilegeAddRole.isAllAllowed());
|
assertTrue(privilegeAddRole.isAllAllowed());
|
||||||
assertEquals(0, privilegeAddRole.getAllowList().size());
|
assertEquals(0, privilegeAddRole.getAllowList().size());
|
||||||
assertEquals(0, privilegeAddRole.getDenyList().size());
|
assertEquals(0, privilegeAddRole.getDenyList().size());
|
||||||
|
|
||||||
IPrivilege privilegeRemRoleFromUser = privilegeAdmin.getPrivilege(
|
Privilege privilegeRemRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_REMOVE_ROLE);
|
||||||
PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER);
|
assertTrue(privilegeRemRole.isAllAllowed());
|
||||||
assertTrue(privilegeRemRoleFromUser.isAllAllowed());
|
assertEquals(0, privilegeRemRole.getAllowList().size());
|
||||||
assertEquals(0, privilegeRemRoleFromUser.getAllowList().size());
|
assertEquals(0, privilegeRemRole.getDenyList().size());
|
||||||
assertEquals(0, privilegeRemRoleFromUser.getDenyList().size());
|
|
||||||
|
|
||||||
// AppUser
|
// AppUser
|
||||||
Role appUser = findRole("AppUser", roles);
|
Role appUser = findRole("AppUser", roles);
|
||||||
|
@ -236,7 +315,7 @@ public class XmlTest {
|
||||||
assertEquals(new HashSet<>(Collections.singletonList("li.strolch.privilege.test.model.TestRestrictable")),
|
assertEquals(new HashSet<>(Collections.singletonList("li.strolch.privilege.test.model.TestRestrictable")),
|
||||||
appUser.getPrivilegeNames());
|
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("li.strolch.privilege.test.model.TestRestrictable", testRestrictable.getName());
|
||||||
assertEquals("DefaultPrivilege", testRestrictable.getPolicy());
|
assertEquals("DefaultPrivilege", testRestrictable.getPolicy());
|
||||||
assertTrue(testRestrictable.isAllAllowed());
|
assertTrue(testRestrictable.isAllAllowed());
|
||||||
|
@ -251,7 +330,7 @@ public class XmlTest {
|
||||||
containsInAnyOrder("li.strolch.privilege.handler.SystemAction",
|
containsInAnyOrder("li.strolch.privilege.handler.SystemAction",
|
||||||
"li.strolch.privilege.test.model.TestSystemRestrictable"));
|
"li.strolch.privilege.test.model.TestSystemRestrictable"));
|
||||||
|
|
||||||
IPrivilege testSystemUserAction = systemAdminPrivileges.getPrivilege(
|
Privilege testSystemUserAction = systemAdminPrivileges.getPrivilege(
|
||||||
"li.strolch.privilege.handler.SystemAction");
|
"li.strolch.privilege.handler.SystemAction");
|
||||||
assertEquals("li.strolch.privilege.handler.SystemAction", testSystemUserAction.getName());
|
assertEquals("li.strolch.privilege.handler.SystemAction", testSystemUserAction.getName());
|
||||||
assertEquals("DefaultPrivilege", testSystemUserAction.getPolicy());
|
assertEquals("DefaultPrivilege", testSystemUserAction.getPolicy());
|
||||||
|
@ -259,7 +338,7 @@ public class XmlTest {
|
||||||
assertEquals(1, testSystemUserAction.getAllowList().size());
|
assertEquals(1, testSystemUserAction.getAllowList().size());
|
||||||
assertEquals(1, testSystemUserAction.getDenyList().size());
|
assertEquals(1, testSystemUserAction.getDenyList().size());
|
||||||
|
|
||||||
IPrivilege testSystemRestrictable = systemAdminPrivileges.getPrivilege(
|
Privilege testSystemRestrictable = systemAdminPrivileges.getPrivilege(
|
||||||
"li.strolch.privilege.test.model.TestSystemRestrictable");
|
"li.strolch.privilege.test.model.TestSystemRestrictable");
|
||||||
assertEquals("li.strolch.privilege.test.model.TestSystemRestrictable", testSystemRestrictable.getName());
|
assertEquals("li.strolch.privilege.test.model.TestSystemRestrictable", testSystemRestrictable.getName());
|
||||||
assertEquals("DefaultPrivilege", testSystemRestrictable.getPolicy());
|
assertEquals("DefaultPrivilege", testSystemRestrictable.getPolicy());
|
||||||
|
@ -274,7 +353,7 @@ public class XmlTest {
|
||||||
MatcherAssert.assertThat(restrictedRole.getPrivilegeNames(),
|
MatcherAssert.assertThat(restrictedRole.getPrivilegeNames(),
|
||||||
containsInAnyOrder("li.strolch.privilege.handler.SystemAction"));
|
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("li.strolch.privilege.handler.SystemAction", testSystemUserAction2.getName());
|
||||||
assertEquals("DefaultPrivilege", testSystemUserAction2.getPolicy());
|
assertEquals("DefaultPrivilege", testSystemUserAction2.getPolicy());
|
||||||
assertFalse(testSystemUserAction2.isAllAllowed());
|
assertFalse(testSystemUserAction2.isAllAllowed());
|
||||||
|
@ -295,36 +374,42 @@ public class XmlTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canWriteUsers() {
|
public void canWriteUsers() throws XMLStreamException, IOException {
|
||||||
|
|
||||||
Map<String, String> propertyMap;
|
Map<String, String> propertyMap;
|
||||||
|
Set<String> groups;
|
||||||
Set<String> userRoles;
|
Set<String> userRoles;
|
||||||
|
|
||||||
List<User> users = new ArrayList<>();
|
List<User> users = new ArrayList<>();
|
||||||
propertyMap = new HashMap<>();
|
propertyMap = new HashMap<>();
|
||||||
propertyMap.put("prop1", "value1");
|
propertyMap.put("prop1", "value1");
|
||||||
|
groups = new HashSet<>();
|
||||||
|
groups.add("group1");
|
||||||
userRoles = new HashSet<>();
|
userRoles = new HashSet<>();
|
||||||
userRoles.add("role1");
|
userRoles.add("role1");
|
||||||
UserHistory history = new UserHistory();
|
UserHistory history = UserHistory.EMPTY.withFirstLogin(
|
||||||
history.setFirstLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
||||||
User user1 = new User("1", "user1",
|
User user1 = new User("1", "user1",
|
||||||
new PasswordCrypt("blabla".getBytes(), "blabla".getBytes(), "PBKDF2WithHmacSHA512", 10000, 256), "Bob",
|
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);
|
users.add(user1);
|
||||||
|
|
||||||
propertyMap = new HashMap<>();
|
propertyMap = new HashMap<>();
|
||||||
propertyMap.put("prop2", "value2");
|
propertyMap.put("prop2", "value2");
|
||||||
|
groups = new HashSet<>();
|
||||||
|
groups.add("group2");
|
||||||
userRoles = new HashSet<>();
|
userRoles = new HashSet<>();
|
||||||
userRoles.add("role2");
|
userRoles.add("role2");
|
||||||
history = new UserHistory();
|
history = UserHistory.EMPTY.withFirstLogin(
|
||||||
history.setFirstLogin(ZonedDateTime.of(LocalDateTime.of(2020, 1, 2, 2, 3, 4, 5), ZoneId.systemDefault()));
|
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()));
|
.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),
|
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);
|
users.add(user2);
|
||||||
|
|
||||||
File modelFile = new File(TARGET_TEST + "PrivilegeUsersTest.xml");
|
File modelFile = new File(TARGET_TEST + "PrivilegeUsersTest.xml");
|
||||||
PrivilegeUsersDomWriter configSaxWriter = new PrivilegeUsersDomWriter(users, modelFile);
|
PrivilegeUsersSaxWriter configSaxWriter = new PrivilegeUsersSaxWriter(users, modelFile);
|
||||||
configSaxWriter.write();
|
configSaxWriter.write();
|
||||||
|
|
||||||
PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader(true);
|
PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader(true);
|
||||||
|
@ -342,8 +427,8 @@ public class XmlTest {
|
||||||
assertEquals(user1.getFirstname(), parsedUser1.getFirstname());
|
assertEquals(user1.getFirstname(), parsedUser1.getFirstname());
|
||||||
assertEquals(user1.getLastname(), parsedUser1.getLastname());
|
assertEquals(user1.getLastname(), parsedUser1.getLastname());
|
||||||
assertEquals(user1.getLocale(), parsedUser1.getLocale());
|
assertEquals(user1.getLocale(), parsedUser1.getLocale());
|
||||||
assertArrayEquals(user1.getPasswordCrypt().getPassword(), parsedUser1.getPasswordCrypt().getPassword());
|
assertArrayEquals(user1.getPasswordCrypt().password(), parsedUser1.getPasswordCrypt().password());
|
||||||
assertArrayEquals(user1.getPasswordCrypt().getSalt(), parsedUser1.getPasswordCrypt().getSalt());
|
assertArrayEquals(user1.getPasswordCrypt().salt(), parsedUser1.getPasswordCrypt().salt());
|
||||||
assertEquals(user1.getProperties(), parsedUser1.getProperties());
|
assertEquals(user1.getProperties(), parsedUser1.getProperties());
|
||||||
assertEquals(user1.getUserId(), parsedUser1.getUserId());
|
assertEquals(user1.getUserId(), parsedUser1.getUserId());
|
||||||
assertEquals(user1.getUserState(), parsedUser1.getUserState());
|
assertEquals(user1.getUserState(), parsedUser1.getUserState());
|
||||||
|
@ -352,8 +437,8 @@ public class XmlTest {
|
||||||
assertEquals(user2.getFirstname(), parsedUser2.getFirstname());
|
assertEquals(user2.getFirstname(), parsedUser2.getFirstname());
|
||||||
assertEquals(user2.getLastname(), parsedUser2.getLastname());
|
assertEquals(user2.getLastname(), parsedUser2.getLastname());
|
||||||
assertEquals(user2.getLocale(), parsedUser2.getLocale());
|
assertEquals(user2.getLocale(), parsedUser2.getLocale());
|
||||||
assertArrayEquals(user2.getPasswordCrypt().getPassword(), parsedUser2.getPasswordCrypt().getPassword());
|
assertArrayEquals(user2.getPasswordCrypt().password(), parsedUser2.getPasswordCrypt().password());
|
||||||
assertArrayEquals(user2.getPasswordCrypt().getSalt(), parsedUser2.getPasswordCrypt().getSalt());
|
assertArrayEquals(user2.getPasswordCrypt().salt(), parsedUser2.getPasswordCrypt().salt());
|
||||||
assertEquals(user2.getProperties(), parsedUser2.getProperties());
|
assertEquals(user2.getProperties(), parsedUser2.getProperties());
|
||||||
assertEquals(user2.getUserId(), parsedUser2.getUserId());
|
assertEquals(user2.getUserId(), parsedUser2.getUserId());
|
||||||
assertEquals(user2.getUserState(), parsedUser2.getUserState());
|
assertEquals(user2.getUserState(), parsedUser2.getUserState());
|
||||||
|
@ -361,13 +446,48 @@ public class XmlTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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<>();
|
List<Role> roles = new ArrayList<>();
|
||||||
Set<String> list = Collections.emptySet();
|
Set<String> list = Collections.emptySet();
|
||||||
privilegeMap = new HashMap<>();
|
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);
|
Role role1 = new Role("role1", privilegeMap);
|
||||||
roles.add(role1);
|
roles.add(role1);
|
||||||
|
|
||||||
|
@ -376,13 +496,13 @@ public class XmlTest {
|
||||||
denyList.add("myself");
|
denyList.add("myself");
|
||||||
Set<String> allowList = new HashSet<>();
|
Set<String> allowList = new HashSet<>();
|
||||||
allowList.add("other");
|
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);
|
Role role2 = new Role("role2", privilegeMap);
|
||||||
roles.add(role2);
|
roles.add(role2);
|
||||||
|
|
||||||
File modelFile = new File(TARGET_TEST + "PrivilegeRolesTest.xml");
|
File modelFile = new File(TARGET_TEST + "PrivilegeRolesTest.xml");
|
||||||
PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, modelFile);
|
PrivilegeRolesSaxWriter writer = new PrivilegeRolesSaxWriter(roles, modelFile);
|
||||||
configSaxWriter.write();
|
writer.write();
|
||||||
|
|
||||||
PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader();
|
PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader();
|
||||||
XmlHelper.parseDocument(modelFile, xmlHandler);
|
XmlHelper.parseDocument(modelFile, xmlHandler);
|
||||||
|
@ -400,8 +520,8 @@ public class XmlTest {
|
||||||
Set<String> privilegeNames = role1.getPrivilegeNames();
|
Set<String> privilegeNames = role1.getPrivilegeNames();
|
||||||
assertEquals(privilegeNames, parsedRole1.getPrivilegeNames());
|
assertEquals(privilegeNames, parsedRole1.getPrivilegeNames());
|
||||||
for (String privilegeName : privilegeNames) {
|
for (String privilegeName : privilegeNames) {
|
||||||
IPrivilege privilege = role1.getPrivilege(privilegeName);
|
Privilege privilege = role1.getPrivilege(privilegeName);
|
||||||
IPrivilege privilege2 = parsedRole1.getPrivilege(privilegeName);
|
Privilege privilege2 = parsedRole1.getPrivilege(privilegeName);
|
||||||
assertNotNull(privilege);
|
assertNotNull(privilege);
|
||||||
assertNotNull(privilege2);
|
assertNotNull(privilege2);
|
||||||
|
|
||||||
|
@ -415,8 +535,8 @@ public class XmlTest {
|
||||||
assertEquals(role2.getPrivilegeNames(), parsedRole2.getPrivilegeNames());
|
assertEquals(role2.getPrivilegeNames(), parsedRole2.getPrivilegeNames());
|
||||||
privilegeNames = role2.getPrivilegeNames();
|
privilegeNames = role2.getPrivilegeNames();
|
||||||
for (String privilegeName : privilegeNames) {
|
for (String privilegeName : privilegeNames) {
|
||||||
IPrivilege privilege = role2.getPrivilege(privilegeName);
|
Privilege privilege = role2.getPrivilege(privilegeName);
|
||||||
IPrivilege privilege2 = parsedRole2.getPrivilege(privilegeName);
|
Privilege privilege2 = parsedRole2.getPrivilege(privilegeName);
|
||||||
assertNotNull(privilege);
|
assertNotNull(privilege);
|
||||||
assertNotNull(privilege2);
|
assertNotNull(privilege2);
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,10 @@ public class DummySsoHandler implements SingleSignOnHandler {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") Map<String, String> map = (Map<String, String>) data;
|
@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());
|
Set<String> roles = Arrays.stream(map.get("roles").split(",")).map(String::trim).collect(Collectors.toSet());
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
return new User(map.get("userId"), map.get("username"), null, map.get("firstName"), map.get("lastName"),
|
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>
|
<Parameters>
|
||||||
<Parameter name="basePath" value="target/${target}"/>
|
<Parameter name="basePath" value="target/${target}"/>
|
||||||
<Parameter name="usersXmlFile" value="PrivilegeUsersMerge.xml"/>
|
<Parameter name="usersXmlFile" value="PrivilegeUsersMerge.xml"/>
|
||||||
|
<Parameter name="groupsXmlFile" value="PrivilegeGroupsMerge.xml"/>
|
||||||
<Parameter name="rolesXmlFile" value="PrivilegeRolesMerge.xml"/>
|
<Parameter name="rolesXmlFile" value="PrivilegeRolesMerge.xml"/>
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</PersistenceHandler>
|
</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>
|
<Roles>
|
||||||
|
|
||||||
<Role name="PrivilegeAdmin">
|
<Role name="PrivilegeAdmin">
|
||||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
|
||||||
<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">
|
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="InvalidateSession" policy="UserSessionAccessPrivilege">
|
<Privilege name="InvalidateSession" policy="UserSessionAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</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">
|
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
|
||||||
<Allow>Reload</Allow>
|
<Allow>GetCertificates</Allow>
|
||||||
<Allow>GetPolicies</Allow>
|
<Allow>GetPolicies</Allow>
|
||||||
<Allow>Persist</Allow>
|
<Allow>Persist</Allow>
|
||||||
<Allow>GetCertificates</Allow>
|
|
||||||
<Allow>PersistSessions</Allow>
|
<Allow>PersistSessions</Allow>
|
||||||
|
<Allow>Reload</Allow>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
|
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
|
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
|
||||||
<Deny>SYSTEM</Deny>
|
|
||||||
<Allow>DISABLED</Allow>
|
|
||||||
<Allow>ENABLED</Allow>
|
|
||||||
</Privilege>
|
|
||||||
<Privilege name="PrivilegeAddRoleToUser" policy="UserAccessPrivilege">
|
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
|
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
|
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
|
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
|
||||||
|
@ -65,15 +36,35 @@
|
||||||
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
|
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeRemoveRoleFromUser" policy="UserAccessPrivilege">
|
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
|
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</Privilege>
|
||||||
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
|
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
|
||||||
<AllAllowed>true</AllAllowed>
|
<AllAllowed>true</AllAllowed>
|
||||||
</Privilege>
|
</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>
|
||||||
|
|
||||||
<Role name="AppUser">
|
<Role name="AppUser">
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
<Lastname>Administrator</Lastname>
|
<Lastname>Administrator</Lastname>
|
||||||
<State>ENABLED</State>
|
<State>ENABLED</State>
|
||||||
<Locale>en-GB</Locale>
|
<Locale>en-GB</Locale>
|
||||||
|
<Groups>
|
||||||
|
<Group>GroupA</Group>
|
||||||
|
</Groups>
|
||||||
<Roles>
|
<Roles>
|
||||||
<Role>PrivilegeAdmin</Role>
|
<Role>PrivilegeAdmin</Role>
|
||||||
<Role>AppUser</Role>
|
<Role>AppUser</Role>
|
||||||
|
@ -21,9 +24,11 @@
|
||||||
<Lastname>Administrator</Lastname>
|
<Lastname>Administrator</Lastname>
|
||||||
<State>ENABLED</State>
|
<State>ENABLED</State>
|
||||||
<Locale>en-GB</Locale>
|
<Locale>en-GB</Locale>
|
||||||
|
<Groups>
|
||||||
|
<Group>AppUserLocationA</Group>
|
||||||
|
</Groups>
|
||||||
<Roles>
|
<Roles>
|
||||||
<Role>PrivilegeAdmin</Role>
|
<Role>PrivilegeAdmin</Role>
|
||||||
<Role>AppUser</Role>
|
|
||||||
</Roles>
|
</Roles>
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="organization" value="eitchnet.ch"/>
|
<Property name="organization" value="eitchnet.ch"/>
|
||||||
|
|
|
@ -23,4 +23,26 @@
|
||||||
</Roles>
|
</Roles>
|
||||||
</User>
|
</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>
|
</Users>
|
|
@ -1,15 +1,5 @@
|
||||||
package li.strolch.execution;
|
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.ComponentContainer;
|
||||||
import li.strolch.agent.api.ObserverEvent;
|
import li.strolch.agent.api.ObserverEvent;
|
||||||
import li.strolch.agent.api.StrolchRealm;
|
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.privilege.model.PrivilegeContext;
|
||||||
import li.strolch.utils.collections.MapOfMaps;
|
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
|
* 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
|
* 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
|
@Override
|
||||||
public boolean isControlling(Activity activity) {
|
public boolean isControlling(Activity activity) {
|
||||||
return this.controllers.containsElement(getDefaultRealm(), activity.getLocator());
|
return this.controllers.containsElement(getDefaultRealm(), activity.getRootElement().getLocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isControlling(String realm, Activity activity) {
|
public boolean isControlling(String realm, Activity activity) {
|
||||||
return this.controllers.containsElement(realm, activity.getLocator());
|
return this.controllers.containsElement(realm, activity.getRootElement().getLocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,12 +83,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Controller getController(Activity activity) {
|
public Controller getController(Activity activity) {
|
||||||
return getController(getDefaultRealm(), activity.getLocator());
|
return getController(getDefaultRealm(), activity.getRootElement().getLocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Controller getController(String realm, Activity activity) {
|
public Controller getController(String realm, Activity activity) {
|
||||||
return this.controllers.getElement(realm, activity.getLocator());
|
return this.controllers.getElement(realm, activity.getRootElement().getLocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -157,7 +157,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
synchronized (this.controllers) {
|
synchronized (this.controllers) {
|
||||||
Map<Locator, Controller> map = this.controllers.getMap(realm);
|
Map<Locator, Controller> map = this.controllers.getMap(realm);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
logger.error("No controllers for realm " + realm);
|
logger.info("No controllers for realm " + realm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,26 +171,28 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addForExecution(Activity activity) {
|
public Controller addForExecution(Activity activity) {
|
||||||
addForExecution(getDefaultRealm(), activity);
|
return addForExecution(getDefaultRealm(), activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addForExecution(String realm, Activity activity) {
|
public Controller addForExecution(String realm, Activity activity) {
|
||||||
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
if (state == ExecutionHandlerState.HaltNew)
|
if (state == ExecutionHandlerState.HaltNew)
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
||||||
|
|
||||||
if (this.controllers.containsElement(realm, activity.getLocator()))
|
Locator locator = activity.getRootElement().getLocator();
|
||||||
throw new IllegalStateException(activity.getLocator() + " is already registered for execution!");
|
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);
|
Controller controller = newController(realm, activity);
|
||||||
this.controllers.addElement(realm, activity.getLocator(), controller);
|
this.controllers.addElement(realm, locator, controller);
|
||||||
notifyObserverAdd(controller);
|
notifyObserverAdd(controller);
|
||||||
|
|
||||||
triggerExecution(realm);
|
triggerExecution(realm);
|
||||||
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,10 +207,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
"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) {
|
if (controller == null) {
|
||||||
controller = newController(realm, activity);
|
controller = newController(realm, activity);
|
||||||
this.controllers.addElement(realm, activity.getLocator(), controller);
|
this.controllers.addElement(realm, locator, controller);
|
||||||
notifyObserverAdd(controller);
|
notifyObserverAdd(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +299,8 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
if (activity.isReadOnly())
|
if (activity.isReadOnly())
|
||||||
activity = activity.getClone(true);
|
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
|
// in execution actions need to be in state STOPPED to restart
|
||||||
activity.findActionsDeep(a -> a.getState().inExecutionPhase()).forEach(a -> {
|
activity.findActionsDeep(a -> a.getState().inExecutionPhase()).forEach(a -> {
|
||||||
|
@ -309,7 +313,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
|
|
||||||
// register for execution
|
// register for execution
|
||||||
Controller controller = newController(realmName, activity);
|
Controller controller = newController(realmName, activity);
|
||||||
this.controllers.addElement(realmName, activity.getLocator(), controller);
|
this.controllers.addElement(realmName, locator, controller);
|
||||||
});
|
});
|
||||||
|
|
||||||
// commit changes to state
|
// commit changes to state
|
||||||
|
|
|
@ -219,7 +219,7 @@ public abstract class ExecutionHandler extends StrolchComponent {
|
||||||
* @throws IllegalStateException
|
* @throws IllegalStateException
|
||||||
* if the default realm is not set!
|
* 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
|
* 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
|
* @param activity
|
||||||
* the {@link 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
|
* 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.StrolchConstants;
|
||||||
import li.strolch.runtime.privilege.PrivilegedRunnable;
|
import li.strolch.runtime.privilege.PrivilegedRunnable;
|
||||||
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
|
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
|
||||||
|
import li.strolch.utils.time.PeriodDuration;
|
||||||
|
|
||||||
import java.time.Duration;
|
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.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -53,6 +57,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
||||||
protected Locator resourceLoc;
|
protected Locator resourceLoc;
|
||||||
protected Locator actionLoc;
|
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
|
* 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
|
* than the actual TX
|
||||||
|
@ -63,6 +69,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
||||||
super(tx);
|
super(tx);
|
||||||
this.tx = tx;
|
this.tx = tx;
|
||||||
this.realm = tx.getRealmName();
|
this.realm = tx.getRealmName();
|
||||||
|
this.futures = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -225,6 +232,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
||||||
public void stop() {
|
public void stop() {
|
||||||
this.stopped = true;
|
this.stopped = true;
|
||||||
try {
|
try {
|
||||||
|
this.futures.forEach(future -> future.cancel(false));
|
||||||
handleStopped();
|
handleStopped();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Stopping failed for " + this.actionLoc, 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
|
* @param state the new state to set
|
||||||
*/
|
*/
|
||||||
protected void setActionState(Action action, State state) {
|
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);
|
action.setState(state);
|
||||||
|
|
||||||
|
@ -270,6 +281,17 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
|
||||||
return action.findObjectivesParam(PARAM_DURATION, true);
|
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}
|
* 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) {
|
public void delay(Duration duration, Runnable runnable) {
|
||||||
long delayMs = duration.toMillis();
|
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;
|
delayMs = 20;
|
||||||
}
|
}
|
||||||
logger.info("Delaying runnable " + runnable + " by " + formatMillisecondsDuration(delayMs));
|
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) {
|
protected void toWarning(LogMessage message) {
|
||||||
cancelWarningTask();
|
cancelWarningTask();
|
||||||
addMessage(message);
|
addMessage(message);
|
||||||
getExecutionHandler().toWarning(this.realm, message.getLocator());
|
getExecutionHandler().toWarning(this.realm, this.actionLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void toExecuted() throws Exception {
|
protected void toExecuted() throws Exception {
|
||||||
|
@ -126,7 +126,7 @@ public class SimpleExecution extends ExecutionPolicy {
|
||||||
stop();
|
stop();
|
||||||
logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage());
|
logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage());
|
||||||
addMessage(message);
|
addMessage(message);
|
||||||
getExecutionHandler().toError(this.realm, message.getLocator());
|
getExecutionHandler().toError(this.realm, this.actionLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setActionStateWithValueChange(Action action, State execution, double value) {
|
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