[New] Implemented keepAlive of strolch sessions
This commit is contained in:
parent
8f645d1af7
commit
5e5289cbc8
|
@ -141,15 +141,15 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
@Override
|
||||
public Certificate authenticate(String username, char[] password) {
|
||||
assertContainerStarted();
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password);
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password, false);
|
||||
writeAudit(certificate, LOGIN, AccessType.CREATE, username);
|
||||
return certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage) {
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive) {
|
||||
assertContainerStarted();
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password, source, usage);
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password, source, usage, keepAlive);
|
||||
writeAudit(certificate, LOGIN, AccessType.CREATE, username);
|
||||
return certificate;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
@Override
|
||||
public Certificate authenticateSingleSignOn(Object data) {
|
||||
assertContainerStarted();
|
||||
Certificate certificate = this.privilegeHandler.authenticateSingleSignOn(data);
|
||||
Certificate certificate = this.privilegeHandler.authenticateSingleSignOn(data, false);
|
||||
writeAudit(certificate, LOGIN, AccessType.CREATE, certificate.getUsername());
|
||||
return certificate;
|
||||
}
|
||||
|
@ -165,11 +165,24 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
@Override
|
||||
public Certificate authenticateSingleSignOn(Object data, String source) {
|
||||
assertContainerStarted();
|
||||
Certificate certificate = this.privilegeHandler.authenticateSingleSignOn(data, source);
|
||||
Certificate certificate = this.privilegeHandler.authenticateSingleSignOn(data, source, false);
|
||||
writeAudit(certificate, LOGIN, AccessType.CREATE, certificate.getUsername());
|
||||
return certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate refreshSession(Certificate certificate, String source) {
|
||||
assertContainerStarted();
|
||||
Certificate refreshedCert = this.privilegeHandler.refresh(certificate, source);
|
||||
writeAudit(refreshedCert, LOGIN, AccessType.CREATE, refreshedCert.getUsername());
|
||||
return refreshedCert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshAllowed() {
|
||||
return this.privilegeHandler.isRefreshAllowed();
|
||||
}
|
||||
|
||||
private void writeAudit(Certificate certificate, String login, AccessType accessType, String username) {
|
||||
StrolchRealm realm = getContainer().getRealm(certificate);
|
||||
try (StrolchTransaction tx = realm.openTx(certificate, login, false).silentThreshold(1, NANOSECONDS)) {
|
||||
|
|
|
@ -45,7 +45,7 @@ public interface PrivilegeHandler {
|
|||
*
|
||||
* @return the certificate
|
||||
*
|
||||
* @see li.strolch.privilege.handler.PrivilegeHandler#authenticate(String, char[])
|
||||
* @see li.strolch.privilege.handler.PrivilegeHandler#authenticate(String, char[], boolean)
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password);
|
||||
|
||||
|
@ -60,12 +60,14 @@ public interface PrivilegeHandler {
|
|||
* the source of the request
|
||||
* @param usage
|
||||
* the usage for this authentication
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
*
|
||||
* @return the certificate
|
||||
*
|
||||
* @see li.strolch.privilege.handler.PrivilegeHandler#authenticate(String, char[])
|
||||
* @see li.strolch.privilege.handler.PrivilegeHandler#authenticate(String, char[], boolean)
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage);
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive);
|
||||
|
||||
/**
|
||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||
|
@ -95,6 +97,25 @@ public interface PrivilegeHandler {
|
|||
*/
|
||||
Certificate authenticateSingleSignOn(Object data, String source) throws PrivilegeException;
|
||||
|
||||
/**
|
||||
* Performs a refresh of the given certificate's session by returning a new certificate
|
||||
*
|
||||
* @param certificate
|
||||
* the certificate to refresh
|
||||
* @param source
|
||||
* the source of the request
|
||||
*
|
||||
* @return certificate a new certificate
|
||||
*/
|
||||
Certificate refreshSession(Certificate certificate, String source);
|
||||
|
||||
/**
|
||||
* Return true if refreshing sessions is allowed
|
||||
*
|
||||
* @return true if refreshing sessions is allowed
|
||||
*/
|
||||
boolean isRefreshAllowed();
|
||||
|
||||
/**
|
||||
* Returns the {@link PrivilegeContext} for the given certificate
|
||||
*
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.io.OutputStream;
|
|||
import java.nio.file.Files;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -124,9 +123,19 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
*/
|
||||
protected SecretKey secretKey;
|
||||
|
||||
/**
|
||||
* flag if session refreshing is allowed
|
||||
*/
|
||||
protected boolean allowSessionRefresh;
|
||||
|
||||
protected PrivilegeConflictResolution privilegeConflictResolution;
|
||||
private String identifier;
|
||||
|
||||
@Override
|
||||
public boolean isRefreshAllowed() {
|
||||
return this.allowSessionRefresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncryptionHandler getEncryptionHandler() throws PrivilegeException {
|
||||
return this.encryptionHandler;
|
||||
|
@ -1038,7 +1047,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
if (ctx.getUserRep().getUsername().equals(newUser.getUsername())) {
|
||||
Certificate cert = ctx.getCertificate();
|
||||
cert = buildCertificate(cert.getUsage(), newUser, cert.getAuthToken(), cert.getSessionId(),
|
||||
cert.getSource(), cert.getLoginTime());
|
||||
cert.getSource(), cert.getLoginTime(), cert.isKeepAlive());
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(cert, newUser);
|
||||
this.privilegeContextMap.put(cert.getSessionId(), privilegeContext);
|
||||
}
|
||||
|
@ -1063,7 +1072,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
|
||||
Certificate cert = ctx.getCertificate();
|
||||
cert = buildCertificate(cert.getUsage(), user, cert.getAuthToken(), cert.getSessionId(),
|
||||
cert.getSource(), cert.getLoginTime());
|
||||
cert.getSource(), cert.getLoginTime(), cert.isKeepAlive());
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(cert, user);
|
||||
this.privilegeContextMap.put(cert.getSessionId(), privilegeContext);
|
||||
}
|
||||
|
@ -1128,7 +1137,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
// create a new certificate, with details of the user
|
||||
Usage usage = userChallenge.getUsage();
|
||||
Certificate certificate = buildCertificate(usage, user, authToken, sessionId, userChallenge.getSource(),
|
||||
new Date());
|
||||
LocalDateTime.now(), false);
|
||||
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user);
|
||||
this.privilegeContextMap.put(sessionId, privilegeContext);
|
||||
|
@ -1145,12 +1154,12 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticate(String username, char[] password) {
|
||||
return authenticate(username, password, "unknown", Usage.ANY);
|
||||
public Certificate authenticate(String username, char[] password, boolean keepAlive) {
|
||||
return authenticate(username, password, "unknown", Usage.ANY, keepAlive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage) {
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive) {
|
||||
DBC.PRE.assertNotEmpty("source must not be empty!", source);
|
||||
|
||||
try {
|
||||
|
@ -1178,7 +1187,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
String sessionId = UUID.randomUUID().toString();
|
||||
|
||||
// create a new certificate, with details of the user
|
||||
Certificate certificate = buildCertificate(usage, user, authToken, sessionId, source, new Date());
|
||||
Certificate certificate = buildCertificate(usage, user, authToken, sessionId, source, LocalDateTime.now(),
|
||||
keepAlive);
|
||||
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user);
|
||||
this.privilegeContextMap.put(sessionId, privilegeContext);
|
||||
|
@ -1204,12 +1214,13 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticateSingleSignOn(Object data) throws PrivilegeException {
|
||||
return authenticateSingleSignOn(data, "unknown");
|
||||
public Certificate authenticateSingleSignOn(Object data, boolean keepAlive) throws PrivilegeException {
|
||||
return authenticateSingleSignOn(data, "unknown", keepAlive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticateSingleSignOn(Object data, String source) throws PrivilegeException {
|
||||
public Certificate authenticateSingleSignOn(Object data, String source, boolean keepAlive)
|
||||
throws PrivilegeException {
|
||||
DBC.PRE.assertNotEmpty("source must not be empty!", source);
|
||||
if (this.ssoHandler == null)
|
||||
throw new IllegalStateException("The SSO Handler is not configured!");
|
||||
|
@ -1234,7 +1245,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
String sessionId = UUID.randomUUID().toString();
|
||||
|
||||
// create a new certificate, with details of the user
|
||||
Certificate certificate = buildCertificate(Usage.ANY, user, authToken, sessionId, source, new Date());
|
||||
Certificate certificate = buildCertificate(Usage.ANY, user, authToken, sessionId, source, LocalDateTime.now(),
|
||||
keepAlive);
|
||||
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user);
|
||||
this.privilegeContextMap.put(sessionId, privilegeContext);
|
||||
|
@ -1247,12 +1259,69 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
return certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate refresh(Certificate certificate, String source) throws AccessDeniedException {
|
||||
DBC.PRE.assertNotNull("certificate must not be null!", certificate);
|
||||
|
||||
try {
|
||||
// username must be at least 2 characters in length
|
||||
if (!this.allowSessionRefresh)
|
||||
throw new AccessDeniedException("Refreshing of sessions not allowed!");
|
||||
|
||||
validate(certificate);
|
||||
|
||||
if (!certificate.isKeepAlive())
|
||||
throw new AccessDeniedException("Refreshing of session not allowed!");
|
||||
|
||||
if (!certificate.getSource().equals(source)) {
|
||||
logger.error("Source of existing session {} is not the same as the refresh request's source {}",
|
||||
certificate.getSource(), source);
|
||||
}
|
||||
|
||||
// check the password
|
||||
User user = this.persistenceHandler.getUser(certificate.getUsername());
|
||||
|
||||
// get 2 auth tokens
|
||||
String authToken = this.encryptionHandler.nextToken();
|
||||
|
||||
// get next session id
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
|
||||
// create a new certificate, with details of the user
|
||||
Certificate refreshedCert = buildCertificate(certificate.getUsage(), user, authToken, sessionId, source,
|
||||
LocalDateTime.now(), true);
|
||||
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(refreshedCert, user);
|
||||
this.privilegeContextMap.put(sessionId, privilegeContext);
|
||||
|
||||
// invalidate the previous session
|
||||
invalidate(certificate);
|
||||
|
||||
persistSessions();
|
||||
|
||||
// log
|
||||
logger.info(MessageFormat
|
||||
.format("User {0} refreshed session: {1}", user.getUsername(), refreshedCert)); //$NON-NLS-1$
|
||||
|
||||
// return the certificate
|
||||
return refreshedCert;
|
||||
|
||||
} catch (PrivilegeException e) {
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = "User {0} failed to refresh session: {1}"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, certificate.getUsername(), e.getMessage());
|
||||
throw new PrivilegeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Certificate buildCertificate(Usage usage, User user, String authToken, String sessionId, String source,
|
||||
Date loginTime) {
|
||||
LocalDateTime loginTime, boolean keepAlive) {
|
||||
DBC.PRE.assertNotEmpty("source must not be empty!", source);
|
||||
Set<String> userRoles = user.getRoles();
|
||||
return new Certificate(usage, sessionId, user.getUsername(), user.getFirstname(), user.getLastname(),
|
||||
user.getUserState(), authToken, source, loginTime, user.getLocale(), userRoles,
|
||||
user.getUserState(), authToken, source, loginTime, keepAlive, user.getLocale(), userRoles,
|
||||
new HashMap<>(user.getProperties()));
|
||||
}
|
||||
|
||||
|
@ -1341,7 +1410,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
}
|
||||
|
||||
// create a new certificate, with details of the user
|
||||
Certificate certificate = buildCertificate(usage, user, authToken, sessionId, source, stub.getLoginTime());
|
||||
Certificate certificate = buildCertificate(usage, user, authToken, sessionId, source, stub.getLoginTime(),
|
||||
stub.isKeepAlive());
|
||||
certificate.setLocale(stub.getLocale());
|
||||
certificate.setLastAccess(stub.getLastAccess());
|
||||
|
||||
|
@ -1538,7 +1608,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
PrivilegeContext privilegeContext = this.privilegeContextMap.remove(certificate.getSessionId());
|
||||
|
||||
// persist sessions
|
||||
persistSessions();
|
||||
if (privilegeContext != null)
|
||||
persistSessions();
|
||||
|
||||
// return true if object was really removed
|
||||
boolean loggedOut = privilegeContext != null;
|
||||
|
@ -1592,7 +1663,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
||||
certificate.setLastAccess(new Date());
|
||||
certificate.setLastAccess(LocalDateTime.now());
|
||||
|
||||
if (!certificate.getSource().equals(this.identifier))
|
||||
throw new IllegalStateException(
|
||||
|
@ -1624,15 +1695,14 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
|
||||
// validate that challenge certificate is not expired (1 hour only)
|
||||
if (sessionCertificate.getUsage() != Usage.ANY) {
|
||||
LocalDateTime dateTime = LocalDateTime
|
||||
.ofInstant(sessionCertificate.getLoginTime().toInstant(), ZoneId.systemDefault());
|
||||
LocalDateTime dateTime = sessionCertificate.getLoginTime();
|
||||
if (dateTime.plusHours(1).isBefore(LocalDateTime.now())) {
|
||||
invalidate(sessionCertificate);
|
||||
throw new NotAuthenticatedException("Certificate has already expired!"); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
certificate.setLastAccess(new Date());
|
||||
certificate.setLastAccess(LocalDateTime.now());
|
||||
|
||||
// TODO decide if we want to assert source did not change!
|
||||
if (!source.equals(SOURCE_UNKNOWN) && !certificate.getSource().equals(source)) {
|
||||
|
@ -1728,6 +1798,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
handleConflictResolutionParam(parameterMap);
|
||||
handleSecretParams(parameterMap);
|
||||
|
||||
this.allowSessionRefresh = Boolean.parseBoolean(parameterMap.get(PARAM_ALLOW_SESSION_REFRESH));
|
||||
|
||||
// validate policies on privileges of Roles
|
||||
for (Role role : persistenceHandler.getAllRoles()) {
|
||||
validatePolicies(role);
|
||||
|
@ -1938,11 +2010,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
* the char array containing the passwort which is to be set to zeroes
|
||||
*/
|
||||
private void clearPassword(char[] password) {
|
||||
if (password != null) {
|
||||
for (int i = 0; i < password.length; i++) {
|
||||
password[i] = 0;
|
||||
}
|
||||
}
|
||||
if (password != null)
|
||||
Arrays.fill(password, (char) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2054,7 +2123,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
|
||||
// create a new certificate, with details of the user
|
||||
Certificate systemUserCertificate = buildCertificate(Usage.ANY, user, authToken, sessionId, this.identifier,
|
||||
new Date());
|
||||
LocalDateTime.now(), false);
|
||||
|
||||
// create and save a new privilege context
|
||||
PrivilegeContext privilegeContext = buildPrivilegeContext(systemUserCertificate, user);
|
||||
|
|
|
@ -166,6 +166,11 @@ public interface PrivilegeHandler {
|
|||
*/
|
||||
String PARAM_SECRET_KEY = "secretKey"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* configuration parameter to define if session refreshing is allowed
|
||||
*/
|
||||
String PARAM_ALLOW_SESSION_REFRESH = "allowSessionRefresh"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* configuration parameter to define a secret salt
|
||||
*/
|
||||
|
@ -608,13 +613,15 @@ public interface PrivilegeHandler {
|
|||
* @param password
|
||||
* the password with which this user is to be authenticated. Null passwords are not accepted and they must meet
|
||||
* the requirements of the {@link #validatePassword(char[])}-method
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user credentials are not valid
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password) throws AccessDeniedException;
|
||||
Certificate authenticate(String username, char[] password, boolean keepAlive) throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Authenticates a user by validating that a {@link User} for the given username and password exist and then returns
|
||||
|
@ -629,26 +636,31 @@ public interface PrivilegeHandler {
|
|||
* the source of the authentication request, i.e. remote IP
|
||||
* @param usage
|
||||
* the usage type for this authentication
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the user credentials are not valid
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage) throws AccessDeniedException;
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive)
|
||||
throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Authenticates a user on a remote Single Sign On service. This is implemented by the
|
||||
*
|
||||
* @param data
|
||||
* the data to perform the SSO
|
||||
* @param keepAlive
|
||||
* should this session be kept alive
|
||||
*
|
||||
* @return the {@link Certificate} for the user
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if something goes wrong with the SSO
|
||||
*/
|
||||
Certificate authenticateSingleSignOn(Object data) 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
|
||||
|
@ -657,13 +669,37 @@ public interface PrivilegeHandler {
|
|||
* the data to perform the SSO
|
||||
* @param source
|
||||
* the source of the SSO authentication
|
||||
* @param keepAlive
|
||||
* may the certificate be kept alive
|
||||
*
|
||||
* @return the {@link Certificate} for the user
|
||||
*
|
||||
* @throws PrivilegeException
|
||||
* if something goes wrong with the SSO
|
||||
*/
|
||||
Certificate authenticateSingleSignOn(Object data, String source) 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
|
||||
*
|
||||
* @param certificate
|
||||
* the certificate for which to perform a refresh
|
||||
* @param source
|
||||
* the source of the refresh request
|
||||
*
|
||||
* @return a {@link Certificate} with which this user may then perform actions
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* if the certificate is now valid, or refreshing is not allowed
|
||||
*/
|
||||
Certificate refresh(Certificate certificate, String source) throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Return true if refreshing sessions is allowed
|
||||
*
|
||||
* @return true if refreshing sessions is allowed
|
||||
*/
|
||||
boolean isRefreshAllowed();
|
||||
|
||||
/**
|
||||
* Invalidates the session for the given {@link Certificate}, effectively logging out the user who was authenticated
|
||||
|
|
|
@ -183,6 +183,11 @@ public class XmlConstants {
|
|||
*/
|
||||
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" :
|
||||
*/
|
||||
|
|
|
@ -18,7 +18,11 @@ package li.strolch.privilege.model;
|
|||
import static li.strolch.privilege.base.PrivilegeConstants.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeConstants;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
|
@ -29,7 +33,7 @@ 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
|
||||
* instance which is always used when performing an access and is returned when a user performs a login through {@link
|
||||
* PrivilegeHandler#authenticate(String, char[])}
|
||||
* PrivilegeHandler#authenticate(String, char[], boolean)}
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -43,13 +47,14 @@ public final class Certificate implements Serializable {
|
|||
private final UserState userState;
|
||||
private final String authToken;
|
||||
private final String source;
|
||||
private final Date loginTime;
|
||||
private final LocalDateTime loginTime;
|
||||
private final boolean keepAlive;
|
||||
|
||||
private final Set<String> userRoles;
|
||||
private final Map<String, String> propertyMap;
|
||||
|
||||
private Locale locale;
|
||||
private Date lastAccess;
|
||||
private LocalDateTime lastAccess;
|
||||
|
||||
/**
|
||||
* Default constructor initializing with all information needed for this certificate
|
||||
|
@ -65,9 +70,9 @@ public final class Certificate implements Serializable {
|
|||
* the users session id
|
||||
* @param username
|
||||
* the users login name
|
||||
* @param firstname
|
||||
* @param firstName
|
||||
* the users first name
|
||||
* @param lastname
|
||||
* @param lastName
|
||||
* the users last name
|
||||
* @param authToken
|
||||
* the authentication token defining the users unique session and is a private field of this certificate.
|
||||
|
@ -79,9 +84,9 @@ public final class Certificate implements Serializable {
|
|||
* a {@link Map} containing string value pairs of properties for the logged in user. These properties can be
|
||||
* edited and can be used for the user to change settings of this session
|
||||
*/
|
||||
public Certificate(Usage usage, String sessionId, String username, String firstname, String lastname,
|
||||
UserState userState, String authToken, String source, Date loginTime, Locale locale, Set<String> userRoles,
|
||||
Map<String, String> propertyMap) {
|
||||
public Certificate(Usage usage, String sessionId, String username, String firstName, String lastName,
|
||||
UserState userState, String authToken, String source, LocalDateTime loginTime, boolean keepAlive,
|
||||
Locale locale, Set<String> userRoles, Map<String, String> propertyMap) {
|
||||
|
||||
// validate arguments are not null
|
||||
if (StringHelper.isEmpty(sessionId)) {
|
||||
|
@ -106,12 +111,13 @@ public final class Certificate implements Serializable {
|
|||
this.usage = usage;
|
||||
this.sessionId = sessionId;
|
||||
this.username = username;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
this.firstname = firstName;
|
||||
this.lastname = lastName;
|
||||
this.userState = userState;
|
||||
this.authToken = authToken;
|
||||
this.source = source;
|
||||
this.loginTime = loginTime;
|
||||
this.keepAlive = keepAlive;
|
||||
|
||||
// if no locale is given, set default
|
||||
if (locale == null)
|
||||
|
@ -125,7 +131,7 @@ public final class Certificate implements Serializable {
|
|||
this.propertyMap = Collections.unmodifiableMap(propertyMap);
|
||||
|
||||
this.userRoles = Collections.unmodifiableSet(userRoles);
|
||||
this.lastAccess = new Date();
|
||||
this.lastAccess = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public Usage getUsage() {
|
||||
|
@ -224,10 +230,14 @@ public final class Certificate implements Serializable {
|
|||
return userState;
|
||||
}
|
||||
|
||||
public Date getLoginTime() {
|
||||
public LocalDateTime getLoginTime() {
|
||||
return this.loginTime;
|
||||
}
|
||||
|
||||
public boolean isKeepAlive() {
|
||||
return this.keepAlive;
|
||||
}
|
||||
|
||||
public String getAuthToken() {
|
||||
return this.authToken;
|
||||
}
|
||||
|
@ -236,11 +246,11 @@ public final class Certificate implements Serializable {
|
|||
return this.source;
|
||||
}
|
||||
|
||||
public Date getLastAccess() {
|
||||
public LocalDateTime getLastAccess() {
|
||||
return this.lastAccess;
|
||||
}
|
||||
|
||||
public void setLastAccess(Date lastAccess) {
|
||||
public void setLastAccess(LocalDateTime lastAccess) {
|
||||
this.lastAccess = lastAccess;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ public class UserChallenge {
|
|||
private final String challenge;
|
||||
private final String source;
|
||||
private final LocalDateTime initiated;
|
||||
private final Usage usage;
|
||||
private boolean fulfilled;
|
||||
private Usage usage;
|
||||
|
||||
public UserChallenge(Usage usage, User user, String challenge, String source) {
|
||||
this.usage = usage;
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
*/
|
||||
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.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601FormatFactory;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
@ -30,8 +32,8 @@ import org.w3c.dom.Element;
|
|||
*/
|
||||
public class CertificateStubsDomWriter {
|
||||
|
||||
private List<Certificate> certificates;
|
||||
private OutputStream outputStream;
|
||||
private final List<Certificate> certificates;
|
||||
private final OutputStream outputStream;
|
||||
|
||||
public CertificateStubsDomWriter(List<Certificate> certificates, OutputStream outputStream) {
|
||||
this.certificates = certificates;
|
||||
|
@ -42,40 +44,41 @@ public class CertificateStubsDomWriter {
|
|||
|
||||
// create document root
|
||||
Document doc = XmlHelper.createDocument();
|
||||
Element rootElement = doc.createElement(XmlConstants.XML_ROOT_CERTIFICATES);
|
||||
Element rootElement = doc.createElement(XML_ROOT_CERTIFICATES);
|
||||
doc.appendChild(rootElement);
|
||||
|
||||
this.certificates.stream().sorted((c1, c2) -> c1.getSessionId().compareTo(c2.getSessionId())).forEach(cert -> {
|
||||
this.certificates.stream().sorted(comparing(Certificate::getSessionId)).forEach(cert -> {
|
||||
|
||||
// create the certificate element
|
||||
Element certElement = doc.createElement(XmlConstants.XML_CERTIFICATE);
|
||||
Element certElement = doc.createElement(XML_CERTIFICATE);
|
||||
rootElement.appendChild(certElement);
|
||||
|
||||
// sessionId;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_SESSION_ID, cert.getSessionId());
|
||||
certElement.setAttribute(XML_ATTR_SESSION_ID, cert.getSessionId());
|
||||
|
||||
// usage;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_USAGE, cert.getUsage().name());
|
||||
certElement.setAttribute(XML_ATTR_USAGE, cert.getUsage().name());
|
||||
|
||||
// username;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, cert.getUsername());
|
||||
certElement.setAttribute(XML_ATTR_USERNAME, cert.getUsername());
|
||||
|
||||
// authToken;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_AUTH_TOKEN, cert.getAuthToken());
|
||||
certElement.setAttribute(XML_ATTR_AUTH_TOKEN, cert.getAuthToken());
|
||||
|
||||
// source;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_SOURCE, cert.getSource());
|
||||
certElement.setAttribute(XML_ATTR_SOURCE, cert.getSource());
|
||||
|
||||
// locale;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_LOCALE, cert.getLocale().toLanguageTag());
|
||||
certElement.setAttribute(XML_ATTR_LOCALE, cert.getLocale().toLanguageTag());
|
||||
|
||||
// loginTime;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_LOGIN_TIME,
|
||||
ISO8601FormatFactory.getInstance().formatDate(cert.getLoginTime()));
|
||||
certElement.setAttribute(XML_ATTR_LOGIN_TIME, ISO8601.toString(cert.getLoginTime()));
|
||||
|
||||
// lastAccess;
|
||||
certElement.setAttribute(XmlConstants.XML_ATTR_LAST_ACCESS,
|
||||
ISO8601FormatFactory.getInstance().formatDate(cert.getLastAccess()));
|
||||
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
|
||||
|
|
|
@ -16,20 +16,20 @@
|
|||
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.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.helper.XmlConstants;
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601FormatFactory;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
@ -39,7 +39,7 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||
*/
|
||||
public class CertificateStubsSaxReader extends DefaultHandler {
|
||||
|
||||
private InputStream inputStream;
|
||||
private final InputStream inputStream;
|
||||
private List<CertificateStub> stubs;
|
||||
|
||||
public CertificateStubsSaxReader(InputStream inputStream) {
|
||||
|
@ -56,21 +56,20 @@ public class CertificateStubsSaxReader extends DefaultHandler {
|
|||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
|
||||
switch (qName) {
|
||||
case XmlConstants.XML_ROOT_CERTIFICATES:
|
||||
case XML_ROOT_CERTIFICATES:
|
||||
break;
|
||||
case XmlConstants.XML_CERTIFICATE:
|
||||
case XML_CERTIFICATE:
|
||||
|
||||
CertificateStub stub = new CertificateStub();
|
||||
stub.usage = Usage.valueOf(attributes.getValue(XmlConstants.XML_ATTR_USAGE));
|
||||
stub.sessionId = attributes.getValue(XmlConstants.XML_ATTR_SESSION_ID);
|
||||
stub.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME);
|
||||
stub.authToken = attributes.getValue(XmlConstants.XML_ATTR_AUTH_TOKEN);
|
||||
stub.source = attributes.getValue(XmlConstants.XML_ATTR_SOURCE);
|
||||
stub.locale = Locale.forLanguageTag(attributes.getValue(XmlConstants.XML_ATTR_LOCALE));
|
||||
stub.loginTime = ISO8601FormatFactory.getInstance()
|
||||
.parseDate(attributes.getValue(XmlConstants.XML_ATTR_LOGIN_TIME));
|
||||
stub.lastAccess = ISO8601FormatFactory.getInstance()
|
||||
.parseDate(attributes.getValue(XmlConstants.XML_ATTR_LAST_ACCESS));
|
||||
stub.usage = Usage.valueOf(attributes.getValue(XML_ATTR_USAGE));
|
||||
stub.sessionId = attributes.getValue(XML_ATTR_SESSION_ID);
|
||||
stub.username = attributes.getValue(XML_ATTR_USERNAME);
|
||||
stub.authToken = attributes.getValue(XML_ATTR_AUTH_TOKEN);
|
||||
stub.source = attributes.getValue(XML_ATTR_SOURCE);
|
||||
stub.locale = Locale.forLanguageTag(attributes.getValue(XML_ATTR_LOCALE));
|
||||
stub.loginTime = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LOGIN_TIME)).toLocalDateTime();
|
||||
stub.lastAccess = ISO8601.parseToZdt(attributes.getValue(XML_ATTR_LAST_ACCESS)).toLocalDateTime();
|
||||
stub.keepAlive = Boolean.parseBoolean(attributes.getValue(XML_ATTR_KEEP_ALIVE));
|
||||
|
||||
DBC.INTERIM.assertNotEmpty("sessionId missing on sessions data!", stub.sessionId);
|
||||
DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username);
|
||||
|
@ -87,15 +86,16 @@ public class CertificateStubsSaxReader extends DefaultHandler {
|
|||
}
|
||||
}
|
||||
|
||||
public class CertificateStub {
|
||||
public static class CertificateStub {
|
||||
private Usage usage;
|
||||
private String sessionId;
|
||||
private String username;
|
||||
private String authToken;
|
||||
private String source;
|
||||
private Locale locale;
|
||||
private Date loginTime;
|
||||
private Date lastAccess;
|
||||
private LocalDateTime loginTime;
|
||||
private LocalDateTime lastAccess;
|
||||
private boolean keepAlive;
|
||||
|
||||
public Usage getUsage() {
|
||||
return this.usage;
|
||||
|
@ -121,12 +121,16 @@ public class CertificateStubsSaxReader extends DefaultHandler {
|
|||
return locale;
|
||||
}
|
||||
|
||||
public Date getLoginTime() {
|
||||
public LocalDateTime getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
public Date getLastAccess() {
|
||||
public LocalDateTime getLastAccess() {
|
||||
return lastAccess;
|
||||
}
|
||||
|
||||
public boolean isKeepAlive() {
|
||||
return this.keepAlive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class AbstractPrivilegeTest {
|
|||
protected PrivilegeContext ctx;
|
||||
|
||||
protected void login(String username, char[] password) {
|
||||
Certificate certificate = privilegeHandler.authenticate(username, password);
|
||||
Certificate certificate = privilegeHandler.authenticate(username, password, false);
|
||||
assertTrue("Certificate is null!", certificate != null);
|
||||
this.ctx = privilegeHandler.validate(certificate);
|
||||
}
|
||||
|
|
|
@ -390,7 +390,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
}
|
||||
|
||||
// change password back
|
||||
certificate = this.privilegeHandler.authenticate(ADMIN, PASS_TED);
|
||||
certificate = this.privilegeHandler.authenticate(ADMIN, PASS_TED, false);
|
||||
this.privilegeHandler.setUserPassword(certificate, ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
|
||||
this.privilegeHandler.invalidate(certificate);
|
||||
}
|
||||
|
@ -742,7 +742,7 @@ public class PrivilegeTest extends AbstractPrivilegeTest {
|
|||
try {
|
||||
// testFailAuthAsBob
|
||||
// Will fail because user bob is not yet enabled
|
||||
this.privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB));
|
||||
this.privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB), false);
|
||||
fail("User Bob may not authenticate because the user is not yet enabled!");
|
||||
} catch (PrivilegeException e) {
|
||||
String msg = "User bob does not have state ENABLED and can not login!";
|
||||
|
|
|
@ -42,7 +42,7 @@ public class SsoHandlerTest extends AbstractPrivilegeTest {
|
|||
data.put("roles", "PrivilegeAdmin, AppUser");
|
||||
|
||||
// auth
|
||||
Certificate cert = this.privilegeHandler.authenticateSingleSignOn(data);
|
||||
Certificate cert = this.privilegeHandler.authenticateSingleSignOn(data, false);
|
||||
this.ctx = this.privilegeHandler.validate(cert);
|
||||
|
||||
// validate action
|
||||
|
|
|
@ -19,9 +19,7 @@ import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIV
|
|||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_INVALIDATE_SESSION;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -51,13 +49,15 @@ import org.slf4j.LoggerFactory;
|
|||
public class DefaultStrolchSessionHandler extends StrolchComponent implements StrolchSessionHandler {
|
||||
|
||||
public static final String PARAM_SESSION_TTL_MINUTES = "session.ttl.minutes"; //$NON-NLS-1$
|
||||
public static final String PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES = "session.maxKeepAlive.minutes"; //$NON-NLS-1$
|
||||
public static final String PARAM_SESSION_RELOAD_SESSIONS = "session.reload"; //$NON-NLS-1$
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
|
||||
private PrivilegeHandler privilegeHandler;
|
||||
private Map<String, Certificate> certificateMap;
|
||||
private boolean reloadSessions;
|
||||
private long sessionTtl;
|
||||
private int sessionTtlMinutes;
|
||||
private int maxKeepAliveMinutes;
|
||||
|
||||
private ScheduledFuture<?> validateSessionsTask;
|
||||
private Future<?> persistSessionsTask;
|
||||
|
@ -66,9 +66,26 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
super(container, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionTtlMinutes() {
|
||||
return this.sessionTtlMinutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionMaxKeepAliveMinutes() {
|
||||
return this.maxKeepAliveMinutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshAllowed() {
|
||||
return this.privilegeHandler.isRefreshAllowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(ComponentConfiguration configuration) throws Exception {
|
||||
this.sessionTtl = TimeUnit.MINUTES.toMillis(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, Math.max(this.sessionTtlMinutes, 30));
|
||||
this.reloadSessions = configuration.getBoolean(PARAM_SESSION_RELOAD_SESSIONS, false);
|
||||
super.initialize(configuration);
|
||||
}
|
||||
|
@ -133,24 +150,11 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticate(String username, char[] password) {
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive) {
|
||||
DBC.PRE.assertNotEmpty("Username must be set!", username); //$NON-NLS-1$
|
||||
DBC.PRE.assertNotNull("Passwort must be set", password); //$NON-NLS-1$
|
||||
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password);
|
||||
|
||||
this.certificateMap.put(certificate.getAuthToken(), certificate);
|
||||
logger.info(MessageFormat.format("{0} sessions currently active.", this.certificateMap.size())); //$NON-NLS-1$
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate authenticate(String username, char[] password, String source, Usage usage) {
|
||||
DBC.PRE.assertNotEmpty("Username must be set!", username); //$NON-NLS-1$
|
||||
DBC.PRE.assertNotNull("Passwort must be set", password); //$NON-NLS-1$
|
||||
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password, source, usage);
|
||||
Certificate certificate = this.privilegeHandler.authenticate(username, password, source, usage, keepAlive);
|
||||
|
||||
this.certificateMap.put(certificate.getAuthToken(), certificate);
|
||||
logger.info(MessageFormat.format("{0} sessions currently active.", this.certificateMap.size())); //$NON-NLS-1$
|
||||
|
@ -178,6 +182,17 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
return certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate refreshSession(Certificate certificate, String source) {
|
||||
Certificate refreshedSession = this.privilegeHandler.refreshSession(certificate, source);
|
||||
|
||||
invalidate(certificate);
|
||||
this.certificateMap.put(refreshedSession.getAuthToken(), refreshedSession);
|
||||
logger.info(MessageFormat.format("{0} sessions currently active.", this.certificateMap.size())); //$NON-NLS-1$
|
||||
|
||||
return refreshedSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate validate(String authToken) throws StrolchNotAuthenticatedException {
|
||||
DBC.PRE.assertNotEmpty("authToken must be set!", authToken); //$NON-NLS-1$
|
||||
|
@ -298,15 +313,24 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
|||
certificateMap = new HashMap<>(this.certificateMap);
|
||||
}
|
||||
|
||||
LocalDateTime timeOutTime = LocalDateTime.now().minus(sessionTtl, ChronoUnit.MILLIS);
|
||||
ZoneId systemDefault = ZoneId.systemDefault();
|
||||
LocalDateTime maxKeepAliveTime = LocalDateTime.now().minus(this.maxKeepAliveMinutes, ChronoUnit.MINUTES);
|
||||
LocalDateTime timeOutTime = LocalDateTime.now().minus(this.sessionTtlMinutes, ChronoUnit.MINUTES);
|
||||
|
||||
for (Certificate certificate : certificateMap.values()) {
|
||||
Instant lastAccess = certificate.getLastAccess().toInstant();
|
||||
if (timeOutTime.isAfter(LocalDateTime.ofInstant(lastAccess, systemDefault))) {
|
||||
String msg = "Session {0} for user {1} has expired, invalidating session..."; //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format(msg, certificate.getSessionId(), certificate.getUsername()));
|
||||
sessionTimeout(certificate);
|
||||
if (certificate.isKeepAlive()) {
|
||||
|
||||
if (maxKeepAliveTime.isAfter(certificate.getLoginTime())) {
|
||||
String msg = "KeepAlive for session {0} for user {1} has expired, invalidating session..."; //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format(msg, certificate.getSessionId(), certificate.getUsername()));
|
||||
sessionTimeout(certificate);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (timeOutTime.isAfter(certificate.getLastAccess())) {
|
||||
String msg = "Session {0} for user {1} has expired, invalidating session..."; //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format(msg, certificate.getSessionId(), certificate.getUsername()));
|
||||
sessionTimeout(certificate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public class StrolchRestfulConstants {
|
|||
public static final String STROLCH_CERTIFICATE = "strolch.certificate"; //$NON-NLS-1$
|
||||
public static final String STROLCH_REQUEST_SOURCE= "strolch.requestSource"; //$NON-NLS-1$
|
||||
public static final String STROLCH_AUTHORIZATION = "strolch.authorization"; //$NON-NLS-1$
|
||||
public static final String STROLCH_AUTHORIZATION_EXPIRATION_DATE = "strolch.authorization.expirationDate"; //$NON-NLS-1$
|
||||
|
||||
public static final String MSG = "msg";
|
||||
public static final String EXCEPTION_MSG = "exceptionMsg";
|
||||
|
|
|
@ -35,16 +35,25 @@ import li.strolch.rest.model.UserSession;
|
|||
public interface StrolchSessionHandler {
|
||||
|
||||
/**
|
||||
* Authenticates a user with the given credentials
|
||||
* Returns the time to live for a session in minutes
|
||||
*
|
||||
* @param username
|
||||
* the username
|
||||
* @param password
|
||||
* the password
|
||||
*
|
||||
* @return the {@link Certificate} for the logged in user
|
||||
* @return the time to live for a session in minutes
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password);
|
||||
int getSessionTtlMinutes();
|
||||
|
||||
/**
|
||||
* Returns the max keep alive for a session in minutes
|
||||
*
|
||||
* @return the max keep alive for a session in minutes
|
||||
*/
|
||||
int getSessionMaxKeepAliveMinutes();
|
||||
|
||||
/**
|
||||
* Return true if refreshing sessions is allowed
|
||||
*
|
||||
* @return true if refreshing sessions is allowed
|
||||
*/
|
||||
boolean isRefreshAllowed();
|
||||
|
||||
/**
|
||||
* Authenticates a user with the given credentials
|
||||
|
@ -57,10 +66,12 @@ public interface StrolchSessionHandler {
|
|||
* the source of the request
|
||||
* @param usage
|
||||
* the usage for this authentication
|
||||
* @param keepAlive
|
||||
* should the session have a keepAlive
|
||||
*
|
||||
* @return the {@link Certificate} for the logged in user
|
||||
*/
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage);
|
||||
Certificate authenticate(String username, char[] password, String source, Usage usage, boolean keepAlive);
|
||||
|
||||
/**
|
||||
* Performs a single-sign-on with the given data, if SSO is enabled
|
||||
|
@ -84,6 +95,18 @@ public interface StrolchSessionHandler {
|
|||
*/
|
||||
Certificate authenticateSingleSignOn(Object data, String source);
|
||||
|
||||
/**
|
||||
* Performs a refresh of the given certificate's session by returning a new certificate
|
||||
*
|
||||
* @param certificate
|
||||
* the certificate to refresh
|
||||
* @param source
|
||||
* the source of the request
|
||||
*
|
||||
* @return certificate a new certificate
|
||||
*/
|
||||
Certificate refreshSession(Certificate certificate, String source);
|
||||
|
||||
/**
|
||||
* Validates that a {@link Certificate} exists with the given auth token and is still valid
|
||||
*
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package li.strolch.rest.endpoint;
|
||||
|
||||
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_AUTHORIZATION;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_AUTHORIZATION_EXPIRATION_DATE;
|
||||
import static li.strolch.rest.filters.AuthenticationRequestFilter.getRemoteIp;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -22,6 +24,7 @@ import javax.ws.rs.*;
|
|||
import javax.ws.rs.core.*;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Base64;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -36,11 +39,11 @@ import li.strolch.privilege.model.IPrivilege;
|
|||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.Usage;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.StrolchRestfulConstants;
|
||||
import li.strolch.rest.StrolchSessionHandler;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
import li.strolch.utils.helper.ExceptionHelper;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -58,12 +61,12 @@ public class AuthenticationService {
|
|||
public Response authenticate(@Context HttpServletRequest request, @Context HttpHeaders headers, String data) {
|
||||
|
||||
JsonObject login = new JsonParser().parse(data).getAsJsonObject();
|
||||
JsonObject loginResult = new JsonObject();
|
||||
|
||||
try {
|
||||
|
||||
if (!login.has("username") || login.get("username").getAsString().length() < 2) {
|
||||
logger.error("Authentication failed: Username was not given or is too short!");
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", MessageFormat.format("Could not log in due to: {0}",
|
||||
"Username was not given or is too short!")); //$NON-NLS-2$
|
||||
return Response.status(Status.BAD_REQUEST).entity(loginResult.toString()).build();
|
||||
|
@ -71,6 +74,7 @@ public class AuthenticationService {
|
|||
|
||||
if (!login.has("password") || login.get("password").getAsString().length() < 3) {
|
||||
logger.error("Authentication failed: Password was not given or is too short!");
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", MessageFormat.format("Could not log in due to: {0}",
|
||||
"Password was not given or is too short!")); //$NON-NLS-2$
|
||||
return Response.status(Status.BAD_REQUEST).entity(loginResult.toString()).build();
|
||||
|
@ -78,12 +82,14 @@ public class AuthenticationService {
|
|||
|
||||
String username = login.get("username").getAsString();
|
||||
String passwordEncoded = login.get("password").getAsString();
|
||||
boolean keepAlive = login.has("keepAlive") && login.get("keepAlive").getAsBoolean();
|
||||
|
||||
byte[] decode = Base64.getDecoder().decode(passwordEncoded);
|
||||
char[] password = new String(decode).toCharArray();
|
||||
|
||||
if (password.length < 3) {
|
||||
logger.error("Authentication failed: Password was not given or is too short!");
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", MessageFormat.format("Could not log in due to: {0}",
|
||||
"Password was not given or is too short!")); //$NON-NLS-2$
|
||||
return Response.status(Status.BAD_REQUEST).entity(loginResult.toString()).build();
|
||||
|
@ -91,27 +97,31 @@ public class AuthenticationService {
|
|||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
String source = getRemoteIp(request);
|
||||
Certificate certificate = sessionHandler.authenticate(username, password, source, Usage.ANY);
|
||||
Certificate certificate = sessionHandler.authenticate(username, password, source, Usage.ANY, keepAlive);
|
||||
|
||||
return getAuthenticationResponse(request, loginResult, certificate, source);
|
||||
return getAuthenticationResponse(request, certificate, source, true);
|
||||
|
||||
} catch (InvalidCredentialsException e) {
|
||||
logger.error("Authentication failed due to: " + e.getMessage());
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", "Could not log in as the given credentials are invalid"); //$NON-NLS-1$
|
||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
logger.error("Authentication failed due to: " + e.getMessage());
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg",
|
||||
MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-2$
|
||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||
} catch (StrolchException | PrivilegeException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg",
|
||||
MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-2$
|
||||
return Response.status(Status.FORBIDDEN).entity(loginResult.toString()).build();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", MessageFormat.format("{0}: {1}", e.getClass().getName(), msg)); //$NON-NLS-1$
|
||||
return Response.serverError().entity(loginResult.toString()).build();
|
||||
}
|
||||
|
@ -122,33 +132,35 @@ public class AuthenticationService {
|
|||
@Path("sso")
|
||||
public Response authenticateSingleSignOn(@Context HttpServletRequest request, @Context HttpHeaders headers) {
|
||||
|
||||
JsonObject loginResult = new JsonObject();
|
||||
|
||||
try {
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
String source = getRemoteIp(request);
|
||||
Certificate certificate = sessionHandler.authenticateSingleSignOn(request.getUserPrincipal(), source);
|
||||
|
||||
return getAuthenticationResponse(request, loginResult, certificate, source);
|
||||
return getAuthenticationResponse(request, certificate, source, true);
|
||||
|
||||
} catch (InvalidCredentialsException e) {
|
||||
logger.error("Authentication failed due to: " + e.getMessage());
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", "Could not log in as the given credentials are invalid"); //$NON-NLS-1$
|
||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
logger.error("Authentication failed due to: " + e.getMessage());
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg",
|
||||
MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-2$
|
||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||
} catch (StrolchException | PrivilegeException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg",
|
||||
MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-2$
|
||||
return Response.status(Status.FORBIDDEN).entity(loginResult.toString()).build();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
JsonObject loginResult = new JsonObject();
|
||||
loginResult.addProperty("msg", MessageFormat.format("{0}: {1}", e.getClass().getName(), msg)); //$NON-NLS-1$
|
||||
return Response.serverError().entity(loginResult.toString()).build();
|
||||
}
|
||||
|
@ -219,6 +231,68 @@ public class AuthenticationService {
|
|||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("{authToken}")
|
||||
public Response getValidatedSession(@Context HttpServletRequest request, @PathParam("authToken") String authToken) {
|
||||
|
||||
try {
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
String source = getRemoteIp(request);
|
||||
Certificate certificate = sessionHandler.validate(authToken, source);
|
||||
|
||||
return getAuthenticationResponse(request, certificate, source, false);
|
||||
|
||||
} catch (StrolchException | PrivilegeException e) {
|
||||
logger.error("Session validation failed: " + e.getMessage());
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("msg", MessageFormat.format("Session invalid: {0}", e.getMessage()));
|
||||
String json = new Gson().toJson(root);
|
||||
return Response.status(Status.UNAUTHORIZED).entity(json).build();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("msg", MessageFormat.format("Session invalid: {0}: {1}", e.getClass().getName(), msg));
|
||||
String json = new Gson().toJson(root);
|
||||
return Response.serverError().entity(json).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("{authToken}")
|
||||
public Response refreshSession(@Context HttpServletRequest request, @PathParam("authToken") String authToken) {
|
||||
|
||||
try {
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
String source = getRemoteIp(request);
|
||||
Certificate certificate = sessionHandler.validate(authToken, source);
|
||||
|
||||
Certificate refreshedCert = sessionHandler.refreshSession(certificate, source);
|
||||
|
||||
return getAuthenticationResponse(request, refreshedCert, source, true);
|
||||
|
||||
} catch (StrolchException | PrivilegeException e) {
|
||||
logger.error("Session validation failed: " + e.getMessage());
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("msg", MessageFormat.format("Session invalid: {0}", e.getMessage()));
|
||||
String json = new Gson().toJson(root);
|
||||
return Response.status(Status.UNAUTHORIZED).entity(json).build();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("msg", MessageFormat.format("Session invalid: {0}: {1}", e.getClass().getName(), msg));
|
||||
String json = new Gson().toJson(root);
|
||||
return Response.serverError().entity(json).build();
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("challenge")
|
||||
|
@ -268,8 +342,8 @@ public class AuthenticationService {
|
|||
logger.warn(msg);
|
||||
}
|
||||
|
||||
NewCookie cookie = new NewCookie(StrolchRestfulConstants.STROLCH_AUTHORIZATION, certificate.getAuthToken(),
|
||||
"/", null, "Authorization header", (int) TimeUnit.DAYS.toSeconds(1), secureCookie);
|
||||
NewCookie cookie = new NewCookie(STROLCH_AUTHORIZATION, certificate.getAuthToken(), "/", null,
|
||||
"Authorization header", (int) TimeUnit.DAYS.toSeconds(1), secureCookie);
|
||||
|
||||
return Response.ok().entity(jsonObject.toString())//
|
||||
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
||||
|
@ -283,17 +357,37 @@ public class AuthenticationService {
|
|||
}
|
||||
}
|
||||
|
||||
private Response getAuthenticationResponse(HttpServletRequest request, JsonObject loginResult,
|
||||
Certificate certificate, String source) {
|
||||
private Response getAuthenticationResponse(HttpServletRequest request, Certificate certificate, String source,
|
||||
boolean setCookies) {
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
int sessionMaxKeepAliveMinutes = sessionHandler.getSessionMaxKeepAliveMinutes();
|
||||
int cookieMaxAge;
|
||||
if (certificate.isKeepAlive()) {
|
||||
cookieMaxAge = (int) TimeUnit.MINUTES.toSeconds(sessionMaxKeepAliveMinutes);
|
||||
} else {
|
||||
cookieMaxAge = RestfulStrolchComponent.getInstance().getCookieMaxAge();
|
||||
}
|
||||
|
||||
LocalDateTime expirationDate = LocalDateTime.now().plusSeconds(cookieMaxAge);
|
||||
String expirationDateS = ISO8601.toString(expirationDate);
|
||||
|
||||
JsonObject loginResult = new JsonObject();
|
||||
|
||||
PrivilegeHandler privilegeHandler = RestfulStrolchComponent.getInstance().getContainer().getPrivilegeHandler();
|
||||
PrivilegeContext privilegeContext = privilegeHandler.validate(certificate, source);
|
||||
loginResult.addProperty("sessionId", certificate.getSessionId());
|
||||
loginResult.addProperty("authToken", certificate.getAuthToken());
|
||||
String authToken = certificate.getAuthToken();
|
||||
loginResult.addProperty("authToken", authToken);
|
||||
loginResult.addProperty("username", certificate.getUsername());
|
||||
loginResult.addProperty("firstname", certificate.getFirstname());
|
||||
loginResult.addProperty("lastname", certificate.getLastname());
|
||||
loginResult.addProperty("locale", certificate.getLocale().toLanguageTag());
|
||||
loginResult.addProperty("keepAlive", certificate.isKeepAlive());
|
||||
loginResult.addProperty("keepAliveMinutes", sessionMaxKeepAliveMinutes);
|
||||
loginResult.addProperty("cookieMaxAge", cookieMaxAge);
|
||||
loginResult.addProperty("authorizationExpiration", expirationDateS);
|
||||
loginResult.addProperty("refreshAllowed", sessionHandler.isRefreshAllowed());
|
||||
|
||||
if (!certificate.getPropertyMap().isEmpty()) {
|
||||
JsonObject propObj = new JsonObject();
|
||||
|
@ -336,15 +430,24 @@ public class AuthenticationService {
|
|||
}
|
||||
|
||||
boolean secureCookie = RestfulStrolchComponent.getInstance().isSecureCookie();
|
||||
int cookieMaxAge = RestfulStrolchComponent.getInstance().getCookieMaxAge();
|
||||
if (secureCookie && !request.getScheme().equals("https")) {
|
||||
logger.error(
|
||||
"Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!");
|
||||
}
|
||||
NewCookie cookie = new NewCookie(StrolchRestfulConstants.STROLCH_AUTHORIZATION, certificate.getAuthToken(), "/",
|
||||
null, "Authorization header", cookieMaxAge, secureCookie);
|
||||
|
||||
return Response.ok().entity(loginResult.toString())//
|
||||
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
||||
if (setCookies) {
|
||||
NewCookie authCookie = new NewCookie(STROLCH_AUTHORIZATION, authToken, "/", null, "Authorization header",
|
||||
cookieMaxAge, secureCookie);
|
||||
NewCookie authExpirationCookie = new NewCookie(STROLCH_AUTHORIZATION_EXPIRATION_DATE, expirationDateS, "/",
|
||||
null, "Authorization Expiration Date", cookieMaxAge, secureCookie);
|
||||
|
||||
return Response.ok().entity(loginResult.toString()) //
|
||||
.header(HttpHeaders.AUTHORIZATION, authToken) //
|
||||
.cookie(authCookie) //
|
||||
.cookie(authExpirationCookie) //
|
||||
.build();
|
||||
}
|
||||
|
||||
return Response.ok().entity(loginResult.toString()).header(HttpHeaders.AUTHORIZATION, authToken).build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ public class AuthenticationRequestFilter implements ContainerRequestFilter {
|
|||
|
||||
logger.info("Performing basic auth for user " + parts[0] + "...");
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
Certificate certificate = sessionHandler.authenticate(parts[0], parts[1].toCharArray(), remoteIp, Usage.SINGLE);
|
||||
Certificate certificate = sessionHandler.authenticate(parts[0], parts[1].toCharArray(), remoteIp, Usage.SINGLE, false);
|
||||
|
||||
requestContext.setProperty(STROLCH_CERTIFICATE, certificate);
|
||||
requestContext.setProperty(STROLCH_REQUEST_SOURCE, remoteIp);
|
||||
|
|
|
@ -15,36 +15,38 @@
|
|||
*/
|
||||
package li.strolch.rest.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.utils.iso8601.ISO8601FormatFactory;
|
||||
import li.strolch.utils.iso8601.ISO8601;
|
||||
|
||||
public class UserSession {
|
||||
|
||||
private String sessionId;
|
||||
private Date loginTime;
|
||||
private String username;
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
private String source;
|
||||
private Set<String> userRoles;
|
||||
private Locale locale;
|
||||
private Date lastAccess;
|
||||
private final boolean keepAlive;
|
||||
private final String sessionId;
|
||||
private final LocalDateTime loginTime;
|
||||
private final String username;
|
||||
private final String firstName;
|
||||
private final String lastName;
|
||||
private final String source;
|
||||
private final Set<String> userRoles;
|
||||
private final Locale locale;
|
||||
private final LocalDateTime lastAccess;
|
||||
|
||||
public UserSession(Certificate certificate) {
|
||||
this.sessionId = certificate.getSessionId();
|
||||
this.loginTime = certificate.getLoginTime();
|
||||
this.username = certificate.getUsername();
|
||||
this.firstname = certificate.getFirstname();
|
||||
this.lastname = certificate.getLastname();
|
||||
this.firstName = certificate.getFirstname();
|
||||
this.lastName = certificate.getLastname();
|
||||
this.source = certificate.getSource();
|
||||
this.userRoles = certificate.getUserRoles();
|
||||
this.locale = certificate.getLocale();
|
||||
this.keepAlive = certificate.isKeepAlive();
|
||||
this.lastAccess = certificate.getLastAccess();
|
||||
}
|
||||
|
||||
|
@ -52,7 +54,7 @@ public class UserSession {
|
|||
return locale;
|
||||
}
|
||||
|
||||
public Date getLastAccess() {
|
||||
public LocalDateTime getLastAccess() {
|
||||
return lastAccess;
|
||||
}
|
||||
|
||||
|
@ -60,7 +62,7 @@ public class UserSession {
|
|||
return sessionId;
|
||||
}
|
||||
|
||||
public Date getLoginTime() {
|
||||
public LocalDateTime getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
|
@ -69,11 +71,11 @@ public class UserSession {
|
|||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
|
@ -88,14 +90,15 @@ public class UserSession {
|
|||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
jsonObject.addProperty("sessionId", this.sessionId);
|
||||
jsonObject.addProperty("loginTime", ISO8601FormatFactory.getInstance().formatDate(this.loginTime));
|
||||
jsonObject.addProperty("loginTime", ISO8601.toString(this.loginTime));
|
||||
jsonObject.addProperty("username", this.username);
|
||||
jsonObject.addProperty("firstname", this.firstname);
|
||||
jsonObject.addProperty("lastname", this.lastname);
|
||||
jsonObject.addProperty("firstname", this.firstName);
|
||||
jsonObject.addProperty("lastname", this.lastName);
|
||||
jsonObject.addProperty("source", this.source);
|
||||
jsonObject.addProperty("keepAlive", this.keepAlive);
|
||||
|
||||
jsonObject.addProperty("locale", this.locale.toString());
|
||||
jsonObject.addProperty("lastAccess", ISO8601FormatFactory.getInstance().formatDate(this.lastAccess));
|
||||
jsonObject.addProperty("lastAccess", ISO8601.toString(this.lastAccess));
|
||||
|
||||
JsonArray rolesJ = new JsonArray();
|
||||
for (String role : this.userRoles) {
|
||||
|
|
|
@ -18,7 +18,7 @@ package li.strolch.service.test;
|
|||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashSet;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
|
@ -49,16 +49,15 @@ public class ServiceTest extends AbstractServiceTest {
|
|||
this.thrown.expect(PrivilegeException.class);
|
||||
TestService testService = new TestService();
|
||||
getServiceHandler().doService(
|
||||
new Certificate(null, null, null, null, null, null, null, null, new Date(), null, new HashSet<>(),
|
||||
null), testService);
|
||||
new Certificate(null, null, null, null, null, null, null, null, LocalDateTime.now(), false, null,
|
||||
new HashSet<>(), null), testService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailInvalidCertificate2() {
|
||||
TestService testService = new TestService();
|
||||
Certificate badCert = new Certificate(Usage.ANY, "1", "bob", "Bob", "Brown", UserState.ENABLED, "dsdf", "asd",
|
||||
//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
|
||||
new Date(), null, new HashSet<>(), null);
|
||||
LocalDateTime.now(), false, null, new HashSet<>(), null);
|
||||
ServiceResult svcResult = getServiceHandler().doService(badCert, testService);
|
||||
assertThat(svcResult.getThrowable(), instanceOf(NotAuthenticatedException.class));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue