|
|
|
package org.airsonic.player.service;
|
|
|
|
|
|
|
|
import com.auth0.jwt.JWT;
|
|
|
|
import com.auth0.jwt.JWTVerifier;
|
|
|
|
import com.auth0.jwt.algorithms.Algorithm;
|
|
|
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
import org.apache.commons.lang3.time.DateUtils;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import org.springframework.web.util.UriComponents;
|
|
|
|
import org.springframework.web.util.UriComponentsBuilder;
|
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
|
|
public class JWTSecurityService {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(JWTSecurityService.class);
|
|
|
|
|
|
|
|
public static final String JWT_PARAM_NAME = "jwt";
|
|
|
|
public static final String CLAIM_PATH = "path";
|
|
|
|
// TODO make this configurable
|
|
|
|
public static final int DEFAULT_DAYS_VALID_FOR = 7;
|
|
|
|
private static SecureRandom secureRandom = new SecureRandom();
|
|
|
|
|
|
|
|
private final SettingsService settingsService;
|
|
|
|
|
|
|
|
public JWTSecurityService(SettingsService settingsService) {
|
|
|
|
this.settingsService = settingsService;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String generateKey() {
|
|
|
|
BigInteger randomInt = new BigInteger(130, secureRandom);
|
|
|
|
return randomInt.toString(32);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Algorithm getAlgorithm(String jwtKey) {
|
|
|
|
try {
|
|
|
|
return Algorithm.HMAC256(jwtKey);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String createToken(String jwtKey, String path, Date expireDate) {
|
|
|
|
UriComponents components = UriComponentsBuilder.fromUriString(path).build();
|
|
|
|
String query = components.getQuery();
|
|
|
|
String claim = components.getPath() + (!StringUtils.isBlank(query) ? "?" + components.getQuery() : "");
|
|
|
|
logger.debug("Creating token with claim " + claim);
|
|
|
|
return JWT.create()
|
|
|
|
.withClaim(CLAIM_PATH, claim)
|
|
|
|
.withExpiresAt(expireDate)
|
|
|
|
.sign(getAlgorithm(jwtKey));
|
|
|
|
}
|
|
|
|
|
|
|
|
public String addJWTToken(String uri) {
|
|
|
|
return addJWTToken(UriComponentsBuilder.fromUriString(uri)).build().toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public UriComponentsBuilder addJWTToken(UriComponentsBuilder builder) {
|
|
|
|
return addJWTToken(builder, DateUtils.addDays(new Date(), DEFAULT_DAYS_VALID_FOR));
|
|
|
|
}
|
|
|
|
|
|
|
|
public UriComponentsBuilder addJWTToken(UriComponentsBuilder builder, Date expires) {
|
|
|
|
String token = JWTSecurityService.createToken(
|
|
|
|
settingsService.getJWTKey(),
|
|
|
|
builder.toUriString(),
|
|
|
|
expires);
|
|
|
|
builder.queryParam(JWTSecurityService.JWT_PARAM_NAME, token);
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static DecodedJWT verify(String jwtKey, String token) {
|
|
|
|
Algorithm algorithm = JWTSecurityService.getAlgorithm(jwtKey);
|
|
|
|
JWTVerifier verifier = JWT.require(algorithm).build();
|
|
|
|
return verifier.verify(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
public DecodedJWT verify(String credentials) {
|
|
|
|
return verify(settingsService.getJWTKey(), credentials);
|
|
|
|
}
|
|
|
|
}
|