mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 18:14:26 +00:00
Remove options to add IP address in JWT auth token. Fixes #2938
This commit is contained in:
@@ -98,12 +98,6 @@ public abstract class JWTTokenHandler {
|
|||||||
*/
|
*/
|
||||||
protected abstract String getTokenExpirationConfigurationKey();
|
protected abstract String getTokenExpirationConfigurationKey();
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configuration property key for the include ip.
|
|
||||||
* @return the configuration property key
|
|
||||||
*/
|
|
||||||
protected abstract String getTokenIncludeIPConfigurationKey();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the configuration property key for the encryption enable setting.
|
* Get the configuration property key for the encryption enable setting.
|
||||||
* @return the configuration property key
|
* @return the configuration property key
|
||||||
@@ -227,10 +221,6 @@ public abstract class JWTTokenHandler {
|
|||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getIncludeIP() {
|
|
||||||
return configurationService.getBooleanProperty(getTokenIncludeIPConfigurationKey(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getExpirationPeriod() {
|
public long getExpirationPeriod() {
|
||||||
return configurationService.getLongProperty(getTokenExpirationConfigurationKey(), 1800000);
|
return configurationService.getLongProperty(getTokenExpirationConfigurationKey(), 1800000);
|
||||||
}
|
}
|
||||||
@@ -288,7 +278,7 @@ public abstract class JWTTokenHandler {
|
|||||||
if (ePerson == null || StringUtils.isBlank(ePerson.getSessionSalt())) {
|
if (ePerson == null || StringUtils.isBlank(ePerson.getSessionSalt())) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
JWSVerifier verifier = new MACVerifier(buildSigningKey(request, ePerson));
|
JWSVerifier verifier = new MACVerifier(buildSigningKey(ePerson));
|
||||||
|
|
||||||
//If token is valid and not expired return eperson in token
|
//If token is valid and not expired return eperson in token
|
||||||
Date expirationTime = jwtClaimsSet.getExpirationTime();
|
Date expirationTime = jwtClaimsSet.getExpirationTime();
|
||||||
@@ -347,7 +337,7 @@ public abstract class JWTTokenHandler {
|
|||||||
SignedJWT signedJWT = new SignedJWT(
|
SignedJWT signedJWT = new SignedJWT(
|
||||||
new JWSHeader(JWSAlgorithm.HS256), claimsSet);
|
new JWSHeader(JWSAlgorithm.HS256), claimsSet);
|
||||||
|
|
||||||
JWSSigner signer = new MACSigner(buildSigningKey(request, ePerson));
|
JWSSigner signer = new MACSigner(buildSigningKey(ePerson));
|
||||||
signedJWT.sign(signer);
|
signedJWT.sign(signer);
|
||||||
return signedJWT;
|
return signedJWT;
|
||||||
}
|
}
|
||||||
@@ -385,18 +375,18 @@ public abstract class JWTTokenHandler {
|
|||||||
* this way the key is always long enough for the HMAC using SHA-256 algorithm.
|
* this way the key is always long enough for the HMAC using SHA-256 algorithm.
|
||||||
* More information: https://tools.ietf.org/html/rfc7518#section-3.2
|
* More information: https://tools.ietf.org/html/rfc7518#section-3.2
|
||||||
*
|
*
|
||||||
* @param request
|
* @param ePerson currently authenticated EPerson
|
||||||
* @param ePerson
|
* @return signing key for token
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
protected String buildSigningKey(HttpServletRequest request, EPerson ePerson) {
|
protected String buildSigningKey(EPerson ePerson) {
|
||||||
String ipAddress = "";
|
return getJwtKey() + ePerson.getSessionSalt();
|
||||||
if (getIncludeIP()) {
|
|
||||||
ipAddress = getIpAddress(request);
|
|
||||||
}
|
|
||||||
return getJwtKey() + ePerson.getSessionSalt() + ipAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get IP Address of client. Only used for logging purposes at this time
|
||||||
|
* @param request current request
|
||||||
|
* @return IP address of client
|
||||||
|
*/
|
||||||
private String getIpAddress(HttpServletRequest request) {
|
private String getIpAddress(HttpServletRequest request) {
|
||||||
return clientInfoService.getClientIp(request);
|
return clientInfoService.getClientIp(request);
|
||||||
}
|
}
|
||||||
|
@@ -30,11 +30,6 @@ public class LoginJWTTokenHandler extends JWTTokenHandler {
|
|||||||
return "jwt.login.token.expiration";
|
return "jwt.login.token.expiration";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getTokenIncludeIPConfigurationKey() {
|
|
||||||
return "jwt.login.token.include.ip";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getEncryptionEnabledConfigurationKey() {
|
protected String getEncryptionEnabledConfigurationKey() {
|
||||||
return "jwt.login.encryption.enabled";
|
return "jwt.login.encryption.enabled";
|
||||||
|
@@ -45,7 +45,7 @@ public class ShortLivedJWTTokenHandler extends JWTTokenHandler {
|
|||||||
if (ePerson == null || StringUtils.isBlank(ePerson.getSessionSalt())) {
|
if (ePerson == null || StringUtils.isBlank(ePerson.getSessionSalt())) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
JWSVerifier verifier = new MACVerifier(buildSigningKey(request, ePerson));
|
JWSVerifier verifier = new MACVerifier(buildSigningKey(ePerson));
|
||||||
|
|
||||||
//If token is valid and not expired return eperson in token
|
//If token is valid and not expired return eperson in token
|
||||||
Date expirationTime = jwtClaimsSet.getExpirationTime();
|
Date expirationTime = jwtClaimsSet.getExpirationTime();
|
||||||
@@ -82,11 +82,6 @@ public class ShortLivedJWTTokenHandler extends JWTTokenHandler {
|
|||||||
return "jwt.shortLived.token.expiration";
|
return "jwt.shortLived.token.expiration";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getTokenIncludeIPConfigurationKey() {
|
|
||||||
return "jwt.shortLived.token.include.ip";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getEncryptionEnabledConfigurationKey() {
|
protected String getEncryptionEnabledConfigurationKey() {
|
||||||
return "jwt.shortLived.encryption.enabled";
|
return "jwt.shortLived.encryption.enabled";
|
||||||
|
@@ -476,42 +476,7 @@ public class AuthenticationRestControllerIT extends AbstractControllerIntegratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReuseTokenWithDifferentIPWhenIPStored() throws Exception {
|
public void testReuseTokenWithDifferentIP() throws Exception {
|
||||||
// Enable IP storage in JWT login token
|
|
||||||
configurationService.setProperty("jwt.login.token.include.ip", true);
|
|
||||||
|
|
||||||
String token = getAuthToken(eperson.getEmail(), password);
|
|
||||||
|
|
||||||
getClient(token).perform(get("/api/authn/status"))
|
|
||||||
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.okay", is(true)))
|
|
||||||
.andExpect(jsonPath("$.authenticated", is(true)))
|
|
||||||
.andExpect(jsonPath("$.type", is("status")));
|
|
||||||
|
|
||||||
// Verify a different IP address (behind a proxy, i.e. X-FORWARDED-FOR)
|
|
||||||
// is *not* able to authenticate with same token
|
|
||||||
getClient(token).perform(get("/api/authn/status")
|
|
||||||
.header("X-FORWARDED-FOR", "1.1.1.1"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.okay", is(true)))
|
|
||||||
.andExpect(jsonPath("$.authenticated", is(false)))
|
|
||||||
.andExpect(jsonPath("$.type", is("status")));
|
|
||||||
|
|
||||||
// Verify a different IP address is *not* able to authenticate with same token
|
|
||||||
getClient(token).perform(get("/api/authn/status")
|
|
||||||
.with(ip("1.1.1.1")))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.okay", is(true)))
|
|
||||||
.andExpect(jsonPath("$.authenticated", is(false)))
|
|
||||||
.andExpect(jsonPath("$.type", is("status")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReuseTokenWithDifferentIPWhenIPNotStored() throws Exception {
|
|
||||||
// Disable IP storage in JWT login token
|
|
||||||
configurationService.setProperty("jwt.login.token.include.ip", false);
|
|
||||||
|
|
||||||
String token = getAuthToken(eperson.getEmail(), password);
|
String token = getAuthToken(eperson.getEmail(), password);
|
||||||
|
|
||||||
getClient(token).perform(get("/api/authn/status"))
|
getClient(token).perform(get("/api/authn/status"))
|
||||||
@@ -523,6 +488,8 @@ public class AuthenticationRestControllerIT extends AbstractControllerIntegratio
|
|||||||
|
|
||||||
// Verify a different IP address (behind a proxy, i.e. X-FORWARDED-FOR)
|
// Verify a different IP address (behind a proxy, i.e. X-FORWARDED-FOR)
|
||||||
// is able to authenticate with same token
|
// is able to authenticate with same token
|
||||||
|
// NOTE: We allow tokens to be used across several IPs to support environments where your IP is not static.
|
||||||
|
// Also keep in mind that if a token is used from an untrusted Origin, it will be blocked (see prior test).
|
||||||
getClient(token).perform(get("/api/authn/status")
|
getClient(token).perform(get("/api/authn/status")
|
||||||
.header("X-FORWARDED-FOR", "1.1.1.1"))
|
.header("X-FORWARDED-FOR", "1.1.1.1"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
|
@@ -74,13 +74,6 @@ jwt.login.compression.enabled = true
|
|||||||
# Expiration time of a token in milliseconds
|
# Expiration time of a token in milliseconds
|
||||||
jwt.login.token.expiration = 1800000
|
jwt.login.token.expiration = 1800000
|
||||||
|
|
||||||
# Restrict tokens to a specific ip-address to prevent theft/session hijacking. This is achieved by making the ip-address
|
|
||||||
# a part of the JWT siging key. If this property is set to false then the ip-address won't be used as part of
|
|
||||||
# the signing key of a jwt token and tokens can be shared over multiple ip-addresses.
|
|
||||||
# For security reasons, this defaults to true
|
|
||||||
jwt.login.token.include.ip = true
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------#
|
#---------------------------------------------------------------#
|
||||||
#---Stateless JWT Authentication for downloads of bitstreams----#
|
#---Stateless JWT Authentication for downloads of bitstreams----#
|
||||||
#----------------------among other things-----------------------#
|
#----------------------among other things-----------------------#
|
||||||
@@ -105,9 +98,3 @@ jwt.shortLived.compression.enabled = true
|
|||||||
|
|
||||||
# Expiration time of a token in milliseconds
|
# Expiration time of a token in milliseconds
|
||||||
jwt.shortLived.token.expiration = 2000
|
jwt.shortLived.token.expiration = 2000
|
||||||
|
|
||||||
# Restrict tokens to a specific ip-address to prevent theft/session hijacking. This is achieved by making the ip-address
|
|
||||||
# a part of the JWT siging key. If this property is set to false then the ip-address won't be used as part of
|
|
||||||
# the signing key of a jwt token and tokens can be shared over multiple ip-addresses.
|
|
||||||
# For security reasons, this defaults to true
|
|
||||||
jwt.shortLived.token.include.ip = true
|
|
||||||
|
Reference in New Issue
Block a user