[Fix] Cherry pick changes to AuthenticationService and RestfulStrolchComponent from develop
This commit is contained in:
parent
bc49e95b9f
commit
db2b2acf09
|
@ -36,16 +36,17 @@ import li.strolch.utils.dbc.DBC;
|
|||
*/
|
||||
public class RestfulStrolchComponent extends StrolchComponent {
|
||||
|
||||
private static final String PARAM_CORS_ENABLED = "corsEnabled"; //$NON-NLS-1$
|
||||
private static final String PARAM_CORS_ORIGIN = "corsOrigin"; //$NON-NLS-1$
|
||||
private static final String PARAM_REST_LOGGING = "restLogging"; //$NON-NLS-1$
|
||||
private static final String PARAM_REST_LOGGING_ENTITY = "restLoggingEntity"; //$NON-NLS-1$
|
||||
private static final String PARAM_HTTP_CACHE_MODE = "httpCacheMode"; //$NON-NLS-1$
|
||||
private static final String PARAM_SECURE_COOKIE = "secureCookie"; //$NON-NLS-1$
|
||||
private static final String PARAM_COOKIE_MAX_AGE = "cookieMaxAge"; //$NON-NLS-1$
|
||||
private static final String PARAM_DOMAIN = "domain"; //$NON-NLS-1$
|
||||
private static final String PARAM_BASIC_AUTH_ENABLED = "basicAuthEnabled"; //$NON-NLS-1$
|
||||
private static final String PARAM_HIDE_VERSION_FROM_UNAUTHORIZED_CLIENTS = "hideVersionFromUnauthorizedClients"; //$NON-NLS-1$
|
||||
private static final String PARAM_CORS_ENABLED = "corsEnabled";
|
||||
private static final String PARAM_CORS_ORIGIN = "corsOrigin";
|
||||
private static final String PARAM_REST_LOGGING = "restLogging";
|
||||
private static final String PARAM_REST_LOGGING_ENTITY = "restLoggingEntity";
|
||||
private static final String PARAM_HTTP_CACHE_MODE = "httpCacheMode";
|
||||
private static final String PARAM_SECURE_COOKIE = "secureCookie";
|
||||
private static final String PARAM_COOKIE_MAX_AGE = "cookieMaxAge";
|
||||
private static final String PARAM_DOMAIN = "domain";
|
||||
private static final String PARAM_PATH = "path";
|
||||
private static final String PARAM_BASIC_AUTH_ENABLED = "basicAuthEnabled";
|
||||
private static final String PARAM_HIDE_VERSION_FROM_UNAUTHORIZED_CLIENTS = "hideVersionFromUnauthorizedClients";
|
||||
|
||||
/**
|
||||
* Allowed values:
|
||||
|
@ -58,7 +59,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
*
|
||||
* @see org.glassfish.jersey.server.ServerProperties#TRACING
|
||||
*/
|
||||
private static final String PARAM_REST_TRACING = "restTracing"; //$NON-NLS-1$
|
||||
private static final String PARAM_REST_TRACING = "restTracing";
|
||||
|
||||
/**
|
||||
* Allowed values:
|
||||
|
@ -70,7 +71,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
*
|
||||
* @see org.glassfish.jersey.server.ServerProperties#TRACING_THRESHOLD
|
||||
*/
|
||||
private static final String PARAM_REST_TRACING_THRESHOLD = "restTracingThreshold"; //$NON-NLS-1$
|
||||
private static final String PARAM_REST_TRACING_THRESHOLD = "restTracingThreshold";
|
||||
|
||||
private static RestfulStrolchComponent instance;
|
||||
|
||||
|
@ -82,6 +83,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
private boolean restLoggingEntity;
|
||||
private boolean secureCookie;
|
||||
private String domain;
|
||||
private String path;
|
||||
private int cookieMaxAge;
|
||||
private boolean basicAuthEnabled;
|
||||
private boolean hideVersionFromUnauthorizedClients;
|
||||
|
@ -136,6 +138,18 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
return domain;
|
||||
}
|
||||
|
||||
public boolean isDomainSet() {
|
||||
return this.domain != null;
|
||||
}
|
||||
|
||||
public boolean isPathSet() {
|
||||
return this.path != null;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public boolean isBasicAuthEnabled() {
|
||||
return this.basicAuthEnabled;
|
||||
}
|
||||
|
@ -150,7 +164,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
this.corsEnabled = configuration.getBoolean(PARAM_CORS_ENABLED, Boolean.FALSE);
|
||||
if (this.corsEnabled) {
|
||||
this.corsOrigin = configuration.getString(PARAM_CORS_ORIGIN, null);
|
||||
logger.info("Enabling CORS for origin: " + this.corsOrigin); //$NON-NLS-1$
|
||||
logger.info("Enabling CORS for origin: " + this.corsOrigin);
|
||||
AccessControlResponseFilter.setCorsEnabled(true);
|
||||
AccessControlResponseFilter.setOrigin(this.corsOrigin);
|
||||
}
|
||||
|
@ -158,10 +172,10 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
// restful logging and tracing
|
||||
this.restLogging = configuration.getBoolean(PARAM_REST_LOGGING, Boolean.FALSE);
|
||||
this.restLoggingEntity = configuration.getBoolean(PARAM_REST_LOGGING_ENTITY, Boolean.FALSE);
|
||||
this.restTracing = configuration.getString(PARAM_REST_TRACING, "OFF"); //$NON-NLS-1$
|
||||
this.restTracingThreshold = configuration.getString(PARAM_REST_TRACING_THRESHOLD, "TRACE"); //$NON-NLS-1$
|
||||
this.restTracing = configuration.getString(PARAM_REST_TRACING, "OFF");
|
||||
this.restTracingThreshold = configuration.getString(PARAM_REST_TRACING_THRESHOLD, "TRACE");
|
||||
|
||||
String msg = "Set restLogging={0} with logEntities={1} restTracing={2} with threshold={3}"; //$NON-NLS-1$
|
||||
String msg = "Set restLogging={0} with logEntities={1} restTracing={2} with threshold={3}";
|
||||
logger.info(MessageFormat.format(msg, this.restLogging, this.restLoggingEntity, this.restTracing,
|
||||
this.restTracingThreshold));
|
||||
|
||||
|
@ -174,6 +188,9 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
this.domain = configuration.getString(PARAM_DOMAIN, "");
|
||||
if (this.domain.isEmpty())
|
||||
this.domain = null;
|
||||
this.path = configuration.getString(PARAM_PATH, "");
|
||||
if (this.path.isEmpty())
|
||||
this.path = null;
|
||||
this.basicAuthEnabled = configuration.getBoolean(PARAM_BASIC_AUTH_ENABLED, true);
|
||||
this.hideVersionFromUnauthorizedClients = configuration.getBoolean(PARAM_HIDE_VERSION_FROM_UNAUTHORIZED_CLIENTS,
|
||||
false);
|
||||
|
@ -186,7 +203,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
DBC.PRE.assertNull("Instance is already set! This component is a singleton resource!", instance); //$NON-NLS-1$
|
||||
DBC.PRE.assertNull("Instance is already set! This component is a singleton resource!", instance);
|
||||
instance = this;
|
||||
super.start();
|
||||
}
|
||||
|
@ -201,7 +218,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
|
|||
* @return the RestfulStrolchComponent
|
||||
*/
|
||||
public static RestfulStrolchComponent getInstance() {
|
||||
DBC.PRE.assertNotNull("Not yet initialized!", instance); //$NON-NLS-1$
|
||||
DBC.PRE.assertNotNull("Not yet initialized!", instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ import javax.ws.rs.core.*;
|
|||
import javax.ws.rs.core.Response.Status;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -195,8 +197,8 @@ public class AuthenticationService {
|
|||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
logoutResult
|
||||
.addProperty("msg", MessageFormat.format("{0}: {1}", e.getClass().getName(), msg)); //$NON-NLS-1$
|
||||
logoutResult.addProperty("msg",
|
||||
MessageFormat.format("{0}: {1}", e.getClass().getName(), msg)); //$NON-NLS-1$
|
||||
return Response.serverError().entity(logoutResult.toString()).build();
|
||||
}
|
||||
}
|
||||
|
@ -329,27 +331,19 @@ public class AuthenticationService {
|
|||
String username = jsonObject.get("username").getAsString();
|
||||
String challenge = jsonObject.get("challenge").getAsString();
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
RestfulStrolchComponent restComponent = RestfulStrolchComponent.getInstance();
|
||||
StrolchSessionHandler sessionHandler = restComponent.getSessionHandler();
|
||||
String source = getRemoteIp(request);
|
||||
Certificate certificate = sessionHandler.validateChallenge(username, challenge, source);
|
||||
int sessionMaxKeepAliveMinutes = sessionHandler.getSessionMaxKeepAliveMinutes();
|
||||
int cookieMaxAge = getCookieMaxAge(certificate, restComponent, sessionMaxKeepAliveMinutes);
|
||||
LocalDateTime expirationDate = LocalDateTime.now().plusSeconds(cookieMaxAge);
|
||||
|
||||
jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("authToken", certificate.getAuthToken());
|
||||
JsonObject result = new JsonObject();
|
||||
String authToken = certificate.getAuthToken();
|
||||
result.addProperty("authToken", authToken);
|
||||
|
||||
boolean secureCookie = RestfulStrolchComponent.getInstance().isSecureCookie();
|
||||
if (secureCookie && !request.getScheme().equals("https")) {
|
||||
String msg = "Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!";
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
String domain = RestfulStrolchComponent.getInstance().getDomain();
|
||||
String path = "/;SameSite=Strict";
|
||||
|
||||
NewCookie cookie = new NewCookie(STROLCH_AUTHORIZATION, certificate.getAuthToken(), path, domain,
|
||||
"Authorization header", (int) TimeUnit.DAYS.toSeconds(1), secureCookie);
|
||||
|
||||
return Response.ok().entity(jsonObject.toString())//
|
||||
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
||||
return setCookiesAndReturnResponse(request, restComponent, cookieMaxAge, expirationDate, result, authToken);
|
||||
|
||||
} catch (PrivilegeException e) {
|
||||
logger.error("Challenge validation failed: " + e.getMessage());
|
||||
|
@ -363,21 +357,15 @@ public class AuthenticationService {
|
|||
private Response getAuthenticationResponse(HttpServletRequest request, Certificate certificate, String source,
|
||||
boolean setCookies) {
|
||||
|
||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||
RestfulStrolchComponent restComponent = RestfulStrolchComponent.getInstance();
|
||||
StrolchSessionHandler sessionHandler = restComponent.getSessionHandler();
|
||||
int sessionMaxKeepAliveMinutes = sessionHandler.getSessionMaxKeepAliveMinutes();
|
||||
int cookieMaxAge;
|
||||
if (certificate.isKeepAlive()) {
|
||||
cookieMaxAge = (int) TimeUnit.MINUTES.toSeconds(sessionMaxKeepAliveMinutes);
|
||||
} else {
|
||||
cookieMaxAge = RestfulStrolchComponent.getInstance().getCookieMaxAge();
|
||||
}
|
||||
|
||||
int cookieMaxAge = getCookieMaxAge(certificate, restComponent, sessionMaxKeepAliveMinutes);
|
||||
LocalDateTime expirationDate = LocalDateTime.now().plusSeconds(cookieMaxAge);
|
||||
String expirationDateS = ISO8601.toString(expirationDate);
|
||||
|
||||
JsonObject loginResult = new JsonObject();
|
||||
|
||||
PrivilegeHandler privilegeHandler = RestfulStrolchComponent.getInstance().getContainer().getPrivilegeHandler();
|
||||
PrivilegeHandler privilegeHandler = restComponent.getContainer().getPrivilegeHandler();
|
||||
PrivilegeContext privilegeContext = privilegeHandler.validate(certificate, source);
|
||||
loginResult.addProperty("sessionId", certificate.getSessionId());
|
||||
String authToken = certificate.getAuthToken();
|
||||
|
@ -389,7 +377,7 @@ public class AuthenticationService {
|
|||
loginResult.addProperty("keepAlive", certificate.isKeepAlive());
|
||||
loginResult.addProperty("keepAliveMinutes", sessionMaxKeepAliveMinutes);
|
||||
loginResult.addProperty("cookieMaxAge", cookieMaxAge);
|
||||
loginResult.addProperty("authorizationExpiration", expirationDateS);
|
||||
loginResult.addProperty("authorizationExpiration", ISO8601.toString(expirationDate));
|
||||
loginResult.addProperty("refreshAllowed", sessionHandler.isRefreshAllowed());
|
||||
loginResult.addProperty("usage", certificate.getUsage().getValue());
|
||||
|
||||
|
@ -433,29 +421,55 @@ public class AuthenticationService {
|
|||
}
|
||||
}
|
||||
|
||||
boolean secureCookie = RestfulStrolchComponent.getInstance().isSecureCookie();
|
||||
if (secureCookie && !request.getScheme().equals("https")) {
|
||||
logger.error(
|
||||
"Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!");
|
||||
}
|
||||
|
||||
if (setCookies) {
|
||||
|
||||
String domain = RestfulStrolchComponent.getInstance().getDomain();
|
||||
String path = "/;SameSite=Strict";
|
||||
|
||||
NewCookie authCookie = new NewCookie(STROLCH_AUTHORIZATION, authToken, path, domain,
|
||||
"Strolch Authorization header", cookieMaxAge, secureCookie);
|
||||
NewCookie authExpirationCookie = new NewCookie(STROLCH_AUTHORIZATION_EXPIRATION_DATE, expirationDateS, path,
|
||||
domain, "Strolch Authorization Expiration Date", cookieMaxAge, secureCookie);
|
||||
|
||||
return Response.ok().entity(loginResult.toString()) //
|
||||
.header(HttpHeaders.AUTHORIZATION, authToken) //
|
||||
.cookie(authCookie) //
|
||||
.cookie(authExpirationCookie) //
|
||||
.build();
|
||||
}
|
||||
|
||||
if (setCookies)
|
||||
return setCookiesAndReturnResponse(request, restComponent, cookieMaxAge, expirationDate, loginResult,
|
||||
authToken);
|
||||
return Response.ok().entity(loginResult.toString()).header(HttpHeaders.AUTHORIZATION, authToken).build();
|
||||
}
|
||||
|
||||
private static Response setCookiesAndReturnResponse(HttpServletRequest request,
|
||||
RestfulStrolchComponent restComponent, int cookieMaxAge, LocalDateTime expirationDate,
|
||||
JsonObject loginResult, String authToken) {
|
||||
boolean secureCookie = restComponent.isSecureCookie();
|
||||
if (secureCookie && !request.getScheme().equals("https")) {
|
||||
String msg = "Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!";
|
||||
logger.error(msg);
|
||||
}
|
||||
|
||||
String expirationDateS = ISO8601.toString(expirationDate);
|
||||
String domain = restComponent.isDomainSet() ? restComponent.getDomain() : request.getServerName();
|
||||
String path = (restComponent.isPathSet() ? restComponent.getPath() : "/") + ";SameSite=Strict";
|
||||
|
||||
Date expiry = Date.from(expirationDate.atZone(ZoneId.systemDefault()).toInstant());
|
||||
boolean httpOnly = false;
|
||||
int version = 1;
|
||||
|
||||
NewCookie authCookie = getNewCookie(STROLCH_AUTHORIZATION, authToken, path, domain, version,
|
||||
"Strolch Authorization header", cookieMaxAge, expiry, secureCookie, httpOnly);
|
||||
NewCookie authExpirationCookie = getNewCookie(STROLCH_AUTHORIZATION_EXPIRATION_DATE, expirationDateS, path,
|
||||
domain, version, "Strolch Authorization Expiration Date", cookieMaxAge, expiry, secureCookie, httpOnly);
|
||||
|
||||
return Response.ok().entity(loginResult.toString()) //
|
||||
.header(HttpHeaders.AUTHORIZATION, authToken) //
|
||||
.cookie(authCookie) //
|
||||
.cookie(authExpirationCookie) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private static int getCookieMaxAge(Certificate certificate, RestfulStrolchComponent restComponent,
|
||||
int sessionMaxKeepAliveMinutes) {
|
||||
int cookieMaxAge;
|
||||
if (certificate.isKeepAlive()) {
|
||||
cookieMaxAge = (int) TimeUnit.MINUTES.toSeconds(sessionMaxKeepAliveMinutes);
|
||||
} else {
|
||||
cookieMaxAge = restComponent.getCookieMaxAge();
|
||||
}
|
||||
return cookieMaxAge;
|
||||
}
|
||||
|
||||
private static NewCookie getNewCookie(String strolchAuthorization, String authToken, String path, String domain,
|
||||
int version, String comment, int cookieMaxAge, Date expiry, boolean secureCookie, boolean httpOnly) {
|
||||
return new NewCookie(strolchAuthorization, authToken, path, domain, version, comment, cookieMaxAge, expiry,
|
||||
secureCookie, httpOnly);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue