update oidc+partey
This commit is contained in:
parent
eb829bfa26
commit
b876bad3e7
@ -0,0 +1,67 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.businesslogic;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.bstly.we.model.User;
|
||||
import de.bstly.we.security.LocalRememberMeServices;
|
||||
import de.bstly.we.security.LocalRememberMeServices.ConcurrentToken;
|
||||
|
||||
/**
|
||||
* The Class SessionManager.
|
||||
*/
|
||||
@Component
|
||||
public class SessionManager {
|
||||
|
||||
@Autowired
|
||||
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
|
||||
@Autowired
|
||||
private LocalRememberMeServices rememberMeServices;
|
||||
|
||||
/**
|
||||
* Delete sessions for user.
|
||||
*
|
||||
* @param user the user
|
||||
*/
|
||||
public void deleteSessionsForUser(User user) {
|
||||
Map<String, ? extends Session> usersSessions = sessionRepository.findByPrincipalName(user.getUsername());
|
||||
for (Session session : usersSessions.values()) {
|
||||
if (session.getAttribute("userId") != null && session.getAttribute("userId").equals(user.getId())) {
|
||||
sessionRepository.deleteById(session.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concurrent clean up.
|
||||
*/
|
||||
@Scheduled(cron = "${rememberme.concurrent.cron:0 */5 * * * * }")
|
||||
public void concurrentCleanUp() {
|
||||
Set<String> delete = Sets.newHashSet();
|
||||
|
||||
for (Entry<String, ConcurrentToken> entry : rememberMeServices.getConcurrentTokens().entrySet()) {
|
||||
if (Instant.now().minus(rememberMeServices.getConcurrentTimeout(), ChronoUnit.SECONDS)
|
||||
.isAfter(entry.getValue().getRenewed())) {
|
||||
delete.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (String key : delete) {
|
||||
rememberMeServices.getConcurrentTokens().remove(key);
|
||||
}
|
||||
}
|
||||
}
|
@ -39,8 +39,8 @@ import de.bstly.we.model.PermissionMapping;
|
||||
import de.bstly.we.model.ProfileFieldType;
|
||||
import de.bstly.we.model.User;
|
||||
import de.bstly.we.model.UserProfileField;
|
||||
import de.bstly.we.model.Visibility;
|
||||
import de.bstly.we.model.UserStatus;
|
||||
import de.bstly.we.model.Visibility;
|
||||
|
||||
/**
|
||||
* The Class UserController.
|
||||
|
@ -3,17 +3,42 @@
|
||||
*/
|
||||
package de.bstly.we.security;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
||||
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* The Class LocalRememberMeServices.
|
||||
*/
|
||||
public class LocalRememberMeServices extends PersistentTokenBasedRememberMeServices {
|
||||
|
||||
private PersistentTokenRepository tokenRepository;
|
||||
|
||||
@Value("${rememberme.concurrent.enabled:true}")
|
||||
private boolean concurrent;
|
||||
@Value("${rememberme.concurrent.timeout:120}")
|
||||
private long concurrentTimeout; // default 2 minutes
|
||||
|
||||
private Map<String, ConcurrentToken> concurrentTokens = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Instantiates a new local remember me services.
|
||||
*
|
||||
@ -24,6 +49,7 @@ public class LocalRememberMeServices extends PersistentTokenBasedRememberMeServi
|
||||
public LocalRememberMeServices(String key, UserDetailsService userDetailsService,
|
||||
PersistentTokenRepository tokenRepository) {
|
||||
super(key, userDetailsService, tokenRepository);
|
||||
this.tokenRepository = tokenRepository;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -45,4 +71,174 @@ public class LocalRememberMeServices extends PersistentTokenBasedRememberMeServi
|
||||
return super.rememberMeRequested(request, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
if (cookieTokens.length != 2) {
|
||||
throw new InvalidCookieException("Cookie token did not contain " + 2 + " tokens, but contained '"
|
||||
+ Arrays.asList(cookieTokens) + "'");
|
||||
}
|
||||
String presentedSeries = cookieTokens[0];
|
||||
String presentedToken = cookieTokens[1];
|
||||
PersistentRememberMeToken token = this.tokenRepository.getTokenForSeries(presentedSeries);
|
||||
if (token == null) {
|
||||
// No series match, so we can't authenticate using this cookie
|
||||
throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
|
||||
}
|
||||
|
||||
boolean concurrentToken = false;
|
||||
String newTokenData = generateTokenData();
|
||||
// We have a match for this user/series combination
|
||||
|
||||
this.logger.trace("concurrentTokens: " + concurrentTokens);
|
||||
|
||||
if (!presentedToken.equals(token.getTokenValue())) {
|
||||
if (concurrent && concurrentTokens.containsKey(presentedToken)) {
|
||||
this.logger.debug("found token '" + presentedToken + "' in concurrent tokens");
|
||||
if (concurrentTokens.get(presentedToken).getSeries().equals(presentedSeries)) {
|
||||
this.logger.debug("found series '" + presentedSeries + "' in concurrent tokens");
|
||||
if (Instant.now().minus(concurrentTimeout, ChronoUnit.SECONDS)
|
||||
.isBefore(concurrentTokens.get(presentedToken).getRenewed())) {
|
||||
newTokenData = token.getTokenValue();
|
||||
concurrentToken = true;
|
||||
} else {
|
||||
this.logger.debug("cocurrent token expired!");
|
||||
concurrentTokens.remove(presentedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!concurrentToken) {
|
||||
// Token doesn't match series value. Delete all logins for this user and throw
|
||||
// an exception to warn them.
|
||||
this.tokenRepository.removeUserTokens(token.getUsername());
|
||||
throw new CookieTheftException(this.messages.getMessage(
|
||||
"PersistentTokenBasedRememberMeServices.cookieStolen",
|
||||
"Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack."));
|
||||
}
|
||||
}
|
||||
if (token.getDate().getTime() + getTokenValiditySeconds() * 1000L < System.currentTimeMillis()) {
|
||||
throw new RememberMeAuthenticationException("Remember-me login has expired");
|
||||
}
|
||||
// Token also matches, so login is valid. Update the token value, keeping the
|
||||
// *same* series number.
|
||||
this.logger.debug(LogMessage.format("Refreshing persistent login token for user '%s', series '%s'",
|
||||
token.getUsername(), token.getSeries()));
|
||||
|
||||
if (!concurrentToken && !concurrentTokens.containsKey(presentedToken)) {
|
||||
concurrentTokens.put(presentedToken, new ConcurrentToken(presentedSeries, Instant.now()));
|
||||
}
|
||||
|
||||
PersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(), token.getSeries(),
|
||||
newTokenData, new Date());
|
||||
try {
|
||||
this.tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate());
|
||||
addCookie(newToken, request, response);
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Failed to update token: ", ex);
|
||||
throw new RememberMeAuthenticationException("Autologin failed due to data access problem");
|
||||
}
|
||||
return getUserDetailsService().loadUserByUsername(token.getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the user tokens.
|
||||
*
|
||||
* @param username the username
|
||||
*/
|
||||
public void removeUserTokens(String username) {
|
||||
tokenRepository.removeUserTokens(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the cookie.
|
||||
*
|
||||
* @param token the token
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
*/
|
||||
private void addCookie(PersistentRememberMeToken token, HttpServletRequest request, HttpServletResponse response) {
|
||||
setCookie(new String[] { token.getSeries(), token.getTokenValue() }, getTokenValiditySeconds(), request,
|
||||
response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the concurrent tokens.
|
||||
*
|
||||
* @return the concurrent tokens
|
||||
*/
|
||||
public Map<String, ConcurrentToken> getConcurrentTokens() {
|
||||
if (concurrentTokens == null) {
|
||||
concurrentTokens = Maps.newHashMap();
|
||||
}
|
||||
return concurrentTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the concurrent timeout.
|
||||
*
|
||||
* @return the concurrent timeout
|
||||
*/
|
||||
public long getConcurrentTimeout() {
|
||||
return concurrentTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class ConcurrentToken.
|
||||
*/
|
||||
public static class ConcurrentToken {
|
||||
|
||||
private String series;
|
||||
private Instant renewed;
|
||||
|
||||
/**
|
||||
* Instantiates a new concurrent token.
|
||||
*
|
||||
* @param series the series
|
||||
* @param renewed the renewed
|
||||
*/
|
||||
public ConcurrentToken(String series, Instant renewed) {
|
||||
super();
|
||||
this.series = series;
|
||||
this.renewed = renewed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the series.
|
||||
*
|
||||
* @return the series
|
||||
*/
|
||||
public String getSeries() {
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the series.
|
||||
*
|
||||
* @param series the new series
|
||||
*/
|
||||
public void setSeries(String series) {
|
||||
this.series = series;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the renewed.
|
||||
*
|
||||
* @return the renewed
|
||||
*/
|
||||
public Instant getRenewed() {
|
||||
return renewed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the renewed.
|
||||
*
|
||||
* @param renewed the new renewed
|
||||
*/
|
||||
public void setRenewed(Instant renewed) {
|
||||
this.renewed = renewed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -149,27 +149,21 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
if (!StringUtils.hasText(config.getAccessToken()) || config.getExpires() == null
|
||||
|| config.getExpires().isBefore(Instant.now())) {
|
||||
|
||||
String authHeader = "Basic "
|
||||
+ new String(Base64.getEncoder()
|
||||
.encode(String
|
||||
.format("%s:%s", config.getClientId(), config.getClientSecret())
|
||||
.getBytes()));
|
||||
WebClient.RequestBodySpec request = WebClient.builder().baseUrl(config.getAccountUrl())
|
||||
.build().method(HttpMethod.POST)
|
||||
.uri(uriBuilder -> uriBuilder.path("/api/token").build())
|
||||
String authHeader = "Basic " + new String(Base64.getEncoder()
|
||||
.encode(String.format("%s:%s", config.getClientId(), config.getClientSecret()).getBytes()));
|
||||
WebClient.RequestBodySpec request = WebClient.builder().baseUrl(config.getAccountUrl()).build()
|
||||
.method(HttpMethod.POST).uri(uriBuilder -> uriBuilder.path("/api/token").build())
|
||||
.header(HttpHeaders.AUTHORIZATION, authHeader)
|
||||
.header(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
||||
|
||||
request.bodyValue("grant_type=refresh_token&refresh_token="
|
||||
+ config.getRefreshToken());
|
||||
request.bodyValue("grant_type=refresh_token&refresh_token=" + config.getRefreshToken());
|
||||
|
||||
String jsonString = request.retrieve().bodyToMono(String.class).block();
|
||||
|
||||
if (StringUtils.hasText(jsonString)) {
|
||||
JsonObject response = JsonParser.parseString(jsonString).getAsJsonObject();
|
||||
config.setAccessToken(response.get("access_token").getAsString());
|
||||
config.setExpires(Instant.now().plus(response.get("expires_in").getAsLong(),
|
||||
ChronoUnit.SECONDS));
|
||||
config.setExpires(Instant.now().plus(response.get("expires_in").getAsLong(), ChronoUnit.SECONDS));
|
||||
|
||||
if (response.has("refresh_token")) {
|
||||
config.setRefreshToken(response.get("refresh_token").getAsString());
|
||||
@ -197,8 +191,7 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player").build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
String jsonString = request.retrieve().bodyToMono(String.class).block();
|
||||
|
||||
@ -222,11 +215,9 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
device_ids.add(config.getDeviceId());
|
||||
queryParameters.add("device_ids", device_ids.toString());
|
||||
queryParameters.add("play", "true");
|
||||
request = webClient.method(HttpMethod.PUT)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player")
|
||||
.queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
request = webClient.method(HttpMethod.PUT).uri(
|
||||
uriBuilder -> uriBuilder.path("/v1/me/player").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
request.retrieve().bodyToMono(String.class).block();
|
||||
return getStatus();
|
||||
@ -280,19 +271,15 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
queryParameters.add("context_uri", context_uri);
|
||||
}
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.PUT)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/play")
|
||||
.queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/play").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
try {
|
||||
request.retrieve().bodyToMono(String.class).block();
|
||||
logger.debug("started playback");
|
||||
} catch (Exception e) {
|
||||
if (!StringUtils.hasText(context_uri)
|
||||
&& StringUtils.hasText(config.getFallbackContextId())) {
|
||||
logger.debug("retry to start playback with: "
|
||||
+ config.getFallbackContextId());
|
||||
if (!StringUtils.hasText(context_uri) && StringUtils.hasText(config.getFallbackContextId())) {
|
||||
logger.debug("retry to start playback with: " + config.getFallbackContextId());
|
||||
tryStartPlayback(config.getFallbackContextId());
|
||||
} else {
|
||||
config.setActive(false);
|
||||
@ -321,13 +308,12 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
if (offset != null) {
|
||||
queryParameters.add("offset", String.valueOf(offset));
|
||||
}
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET).uri(
|
||||
uriBuilder -> uriBuilder.path("/v1/search").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/search").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
String jsonString = request.retrieve().bodyToMono(String.class)
|
||||
.onErrorResume(e -> Mono.just(e.getMessage())).block();
|
||||
String jsonString = request.retrieve().bodyToMono(String.class).onErrorResume(e -> Mono.just(e.getMessage()))
|
||||
.block();
|
||||
|
||||
if (StringUtils.hasText(jsonString)) {
|
||||
return JsonParser.parseString(jsonString);
|
||||
@ -352,14 +338,12 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
if (limit != null) {
|
||||
queryParameters.add("limit", String.valueOf(limit));
|
||||
}
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/recently-played")
|
||||
.queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET).uri(
|
||||
uriBuilder -> uriBuilder.path("/v1/me/player/recently-played").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
String jsonString = request.retrieve().bodyToMono(String.class)
|
||||
.onErrorResume(e -> Mono.just(e.getMessage())).block();
|
||||
String jsonString = request.retrieve().bodyToMono(String.class).onErrorResume(e -> Mono.just(e.getMessage()))
|
||||
.block();
|
||||
|
||||
if (StringUtils.hasText(jsonString)) {
|
||||
return JsonParser.parseString(jsonString);
|
||||
@ -396,10 +380,8 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
MultiValueMap<String, String> queryParameters = new LinkedMultiValueMap<String, String>();
|
||||
queryParameters.add("device_id", config.getDeviceId());
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.PUT)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/play")
|
||||
.queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/play").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
JsonObject body = new JsonObject();
|
||||
if (StringUtils.hasText(config.getFallbackContextId())) {
|
||||
@ -419,10 +401,8 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
queryParameters.add("uri", uri);
|
||||
queryParameters.add("device_id", config.getDeviceId());
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.POST)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/queue")
|
||||
.queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/queue").queryParams(queryParameters).build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
request.retrieve().bodyToMono(String.class).block();
|
||||
}
|
||||
@ -468,8 +448,7 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
|
||||
WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/me/player/devices").build())
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer "
|
||||
+ config.getAccessToken());
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken());
|
||||
|
||||
boolean deviceFound = false;
|
||||
|
||||
@ -482,8 +461,7 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
JsonArray devices = response.getAsJsonObject().getAsJsonArray("devices");
|
||||
for (JsonElement deviceElement : devices) {
|
||||
JsonObject device = deviceElement.getAsJsonObject();
|
||||
if (device.has("id")
|
||||
&& device.get("id").getAsString().equals(config.getDeviceId())) {
|
||||
if (device.has("id") && device.get("id").getAsString().equals(config.getDeviceId())) {
|
||||
deviceFound = true;
|
||||
return;
|
||||
}
|
||||
@ -496,8 +474,7 @@ public class JukeboxManager implements SmartInitializingSingleton {
|
||||
try {
|
||||
Runtime.getRuntime().exec(command);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Could execute command: "
|
||||
+ command, e);
|
||||
logger.warn("Could execute command: " + command, e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,8 @@ public class JukeboxController extends BaseController {
|
||||
throw new EntityResponseStatusException(HttpStatus.GONE);
|
||||
}
|
||||
|
||||
if (queueList.containsKey(getCurrentUserId()) && queueList.get(getCurrentUserId())
|
||||
.isAfter(Instant.now().minus(1, ChronoUnit.MINUTES))) {
|
||||
if (queueList.containsKey(getCurrentUserId())
|
||||
&& queueList.get(getCurrentUserId()).isAfter(Instant.now().minus(1, ChronoUnit.MINUTES))) {
|
||||
throw new EntityResponseStatusException(
|
||||
Duration.between(queueList.get(getCurrentUserId()), Instant.now()).getSeconds(),
|
||||
HttpStatus.PAYMENT_REQUIRED);
|
||||
@ -92,10 +92,10 @@ public class JukeboxController extends BaseController {
|
||||
throw new EntityResponseStatusException(HttpStatus.GONE);
|
||||
}
|
||||
|
||||
if (searchList.containsKey(getCurrentUserId()) && searchList.get(getCurrentUserId())
|
||||
.isAfter(Instant.now().minus(3, ChronoUnit.SECONDS))) {
|
||||
throw new EntityResponseStatusException(Duration
|
||||
.between(searchList.get(getCurrentUserId()), Instant.now()).getSeconds(),
|
||||
if (searchList.containsKey(getCurrentUserId())
|
||||
&& searchList.get(getCurrentUserId()).isAfter(Instant.now().minus(3, ChronoUnit.SECONDS))) {
|
||||
throw new EntityResponseStatusException(
|
||||
Duration.between(searchList.get(getCurrentUserId()), Instant.now()).getSeconds(),
|
||||
HttpStatus.PAYMENT_REQUIRED);
|
||||
}
|
||||
}
|
||||
@ -137,9 +137,8 @@ public class JukeboxController extends BaseController {
|
||||
*/
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping("/search")
|
||||
public void search(@RequestParam("q") String query,
|
||||
@RequestParam("offset") Optional<Long> offset, HttpServletResponse response)
|
||||
throws JsonIOException, IOException {
|
||||
public void search(@RequestParam("q") String query, @RequestParam("offset") Optional<Long> offset,
|
||||
HttpServletResponse response) throws JsonIOException, IOException {
|
||||
checkSearchPermission();
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
@ -110,9 +110,8 @@ public class JukeboxManagementController extends BaseController {
|
||||
*/
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/search")
|
||||
public void search(@RequestParam("q") String query,
|
||||
@RequestParam("offset") Optional<Long> offset, HttpServletResponse response)
|
||||
throws JsonIOException, IOException {
|
||||
public void search(@RequestParam("q") String query, @RequestParam("offset") Optional<Long> offset,
|
||||
HttpServletResponse response) throws JsonIOException, IOException {
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
gson.toJson(jukeboxManager.searchTrack(query, offset.orElse(null)), response.getWriter());
|
||||
|
@ -11,7 +11,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationCode;
|
||||
|
||||
/**
|
||||
* The Class OidcAuthorizationCodeManager.
|
||||
|
@ -0,0 +1,141 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.model.OidcAuthorization;
|
||||
import de.bstly.we.oidc.model.QOidcAuthorization;
|
||||
import de.bstly.we.oidc.repository.OidcAuthorizationRepository;
|
||||
|
||||
/**
|
||||
* The Class OidcAuthorizationManager.
|
||||
*/
|
||||
@Service
|
||||
public class OidcAuthorizationManager {
|
||||
|
||||
@Autowired
|
||||
private OidcAuthorizationRepository oidcAuthorizationRepository;
|
||||
|
||||
private QOidcAuthorization qOidcAuthorization = QOidcAuthorization.oidcAuthorization;
|
||||
|
||||
/**
|
||||
* hold codes in memory
|
||||
*/
|
||||
private final Map<String, OidcAuthorizationCode> authorizationCodes = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Gets the authorization.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @return the authorization
|
||||
*/
|
||||
public OidcAuthorization getAuthorization(Long clientId, Long subject) {
|
||||
return oidcAuthorizationRepository
|
||||
.findOne(qOidcAuthorization.client.eq(clientId).and(qOidcAuthorization.subject.eq(subject)))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is authorized.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @param scopes the scopes
|
||||
* @return true, if is authorized
|
||||
*/
|
||||
public boolean isAuthorized(Long clientId, Long subject, Set<String> scopes) {
|
||||
OidcAuthorization oidcAuthorization = getAuthorization(clientId, subject);
|
||||
if (oidcAuthorization == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return scopes == null
|
||||
|| oidcAuthorization.getScopes() != null && oidcAuthorization.getScopes().containsAll(scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @param scopes the scopes
|
||||
* @return the oidc authorization
|
||||
*/
|
||||
public OidcAuthorization authorize(Long clientId, Long subject, Set<String> scopes) {
|
||||
OidcAuthorization oidcAuthorization = getAuthorization(clientId, subject);
|
||||
if (oidcAuthorization == null) {
|
||||
oidcAuthorization = new OidcAuthorization();
|
||||
oidcAuthorization.setClient(clientId);
|
||||
oidcAuthorization.setSubject(subject);
|
||||
oidcAuthorization.setScopes(Sets.newHashSet());
|
||||
}
|
||||
|
||||
oidcAuthorization.getScopes().addAll(scopes);
|
||||
|
||||
return oidcAuthorizationRepository.save(oidcAuthorization);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the authorization.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
*/
|
||||
public void removeAuthorization(Long clientId, Long subject) {
|
||||
OidcAuthorization oidcAuthorization = getAuthorization(clientId, subject);
|
||||
if (oidcAuthorization != null) {
|
||||
oidcAuthorizationRepository.delete(oidcAuthorization);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the code.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param redirectUri the redirect uri
|
||||
* @param scopes the scopes
|
||||
* @param subject the subject
|
||||
* @param nonce the nonce
|
||||
* @param springSession the spring session
|
||||
* @return the oidc authorization code
|
||||
*/
|
||||
public OidcAuthorizationCode createCode(String clientId, URI redirectUri, Set<String> scopes, Long subject,
|
||||
String nonce, String springSession) {
|
||||
OidcAuthorizationCode authorizationCode = new OidcAuthorizationCode(clientId, redirectUri, scopes, subject,
|
||||
nonce);
|
||||
authorizationCode.setSpringSession(springSession);
|
||||
authorizationCodes.put(authorizationCode.getCode(), authorizationCode);
|
||||
return authorizationCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the code.
|
||||
*
|
||||
* @param code the code
|
||||
* @return the code
|
||||
*/
|
||||
public OidcAuthorizationCode getCode(String code) {
|
||||
return authorizationCodes.get(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the code.
|
||||
*
|
||||
* @param code the code
|
||||
*/
|
||||
public void removeCode(String code) {
|
||||
authorizationCodes.remove(code);
|
||||
}
|
||||
}
|
@ -5,19 +5,26 @@ package de.bstly.we.oidc.businesslogic;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.controller.model.OidcClientInfo;
|
||||
import de.bstly.we.oidc.model.OidcAuthorization;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.model.QOidcClient;
|
||||
import de.bstly.we.oidc.repository.OidcClientRepository;
|
||||
|
||||
@ -33,8 +40,32 @@ public class OidcClientManager {
|
||||
|
||||
@Autowired
|
||||
private OidcClientRepository oidcClientRepository;
|
||||
@Autowired
|
||||
private OidcAuthorizationManager oidcAuthorizationManager;
|
||||
private QOidcClient qOidcClient = QOidcClient.oidcClient;
|
||||
|
||||
@Value("${oidc.provider.issuer:}")
|
||||
private String oidcIssuer;
|
||||
|
||||
/**
|
||||
* Gets the issuer.
|
||||
*
|
||||
* @param request the request
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer(HttpServletRequest request) {
|
||||
String issuer = oidcIssuer;
|
||||
|
||||
if (!StringUtils.hasText(issuer)) {
|
||||
issuer = request.getScheme() + "://" + request.getServerName();
|
||||
if (request.getServerPort() != 443 && request.getServerPort() != 80) {
|
||||
issuer += ":" + request.getServerPort();
|
||||
}
|
||||
}
|
||||
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the client.
|
||||
*
|
||||
@ -112,6 +143,16 @@ public class OidcClientManager {
|
||||
return oidcClientRepository.save(oidcClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the.
|
||||
*
|
||||
* @param id the id
|
||||
* @return the oidc client
|
||||
*/
|
||||
public OidcClient get(Long id) {
|
||||
return oidcClientRepository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the by client id.
|
||||
*
|
||||
@ -180,4 +221,38 @@ public class OidcClientManager {
|
||||
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
|
||||
return oidcClientRepository.findAll(PageRequest.of(page, size, sort));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client info.
|
||||
*
|
||||
* @param client the client
|
||||
* @param subject the subject
|
||||
* @return the client info
|
||||
*/
|
||||
public OidcClientInfo getClientInfo(OidcClient client, Long subject) {
|
||||
|
||||
OidcClientInfo info = new OidcClientInfo();
|
||||
info.setClientId(client.getClientId());
|
||||
info.setName(client.getClientName());
|
||||
info.setLoginUrl(client.getLoginUrl());
|
||||
info.setFrontchannelLogoutUri(client.getFrontchannelLogoutUri());
|
||||
info.setFrontchannelLogoutSessionRequired(client.isFrontchannelLogoutSessionRequired());
|
||||
info.setBackchannelLogout(StringUtils.hasText(client.getBackchannelLogoutUri()));
|
||||
|
||||
info.setAuthorize(client.isAuthorize());
|
||||
info.setScopes(client.getScopes());
|
||||
info.setSessions(Lists.newArrayList());
|
||||
|
||||
if (info.getScopes() == null) {
|
||||
info.setScopes(Sets.newHashSet());
|
||||
}
|
||||
|
||||
OidcAuthorization authorization = oidcAuthorizationManager.getAuthorization(client.getId(), subject);
|
||||
|
||||
if (authorization != null) {
|
||||
info.setAuthorizedScopes(authorization.getScopes());
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,442 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.JWSSigner;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
import de.bstly.we.jwt.businesslogic.JwtKeyManager;
|
||||
import de.bstly.we.jwt.model.JwtKey;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcSession;
|
||||
import de.bstly.we.oidc.model.QOidcSession;
|
||||
import de.bstly.we.oidc.repository.OidcSessionRepository;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* The Class OidcSessionManager.
|
||||
*/
|
||||
@Service
|
||||
public class OidcSessionManager {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(OidcSessionManager.class);
|
||||
|
||||
@Autowired
|
||||
private OidcSessionRepository oidcSessionRepository;
|
||||
@Autowired
|
||||
private OidcClientManager oidcRegisteredClientManager;
|
||||
@Autowired
|
||||
private JwtKeyManager jwtKeyManager;
|
||||
|
||||
protected WebClient webClient = WebClient.builder().build();
|
||||
|
||||
private QOidcSession qOidcSession = QOidcSession.oidcSession;
|
||||
|
||||
public static final int SID_LENGTH = 32;
|
||||
public static final int JWT_ID_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Creates the sid.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
public String createSid() {
|
||||
String sid = new StringBuilder(RandomStringUtils.random(SID_LENGTH, true, true)).insert(8, "-").insert(13, "-")
|
||||
.insert(18, "-").insert(23, "-").toString();
|
||||
|
||||
while (oidcSessionRepository.exists(qOidcSession.sid.eq(sid))) {
|
||||
sid = new StringBuilder(RandomStringUtils.random(SID_LENGTH, true, true)).insert(8, "-").insert(13, "-")
|
||||
.insert(18, "-").insert(23, "-").toString();
|
||||
}
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the session.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @param idToken the id token
|
||||
* @param sid the sid
|
||||
* @param springSession the spring session
|
||||
* @return the oidc session
|
||||
* @throws JOSEException the JOSE exception
|
||||
*/
|
||||
public OidcSession createSession(Long clientId, Long subject, String idToken, String sid, String springSession)
|
||||
throws JOSEException {
|
||||
|
||||
OidcSession session = new OidcSession();
|
||||
session.setClientId(clientId);
|
||||
session.setSubject(subject);
|
||||
session.setIdToken(idToken);
|
||||
session.setSid(sid);
|
||||
session.setSpringSession(springSession);
|
||||
return oidcSessionRepository.save(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the by sid.
|
||||
*
|
||||
* @param sid the sid
|
||||
* @return the by sid
|
||||
*/
|
||||
public OidcSession getBySid(String sid) {
|
||||
Assert.isTrue(StringUtils.hasText(sid), "No sid defined!");
|
||||
return oidcSessionRepository.findOne(qOidcSession.sid.eq(sid)).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the by id token.
|
||||
*
|
||||
* @param idToken the id token
|
||||
* @return the by id token
|
||||
*/
|
||||
public OidcSession getByIdToken(String idToken) {
|
||||
return oidcSessionRepository.findOne(qOidcSession.idToken.eq(idToken)).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the all by spring session.
|
||||
*
|
||||
* @param springSession the spring session
|
||||
* @return the all by spring session
|
||||
*/
|
||||
public List<OidcSession> getAllBySpringSession(String springSession) {
|
||||
return Lists.newArrayList(oidcSessionRepository.findAll(qOidcSession.springSession.eq(springSession)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the all by target.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @return the all by target
|
||||
*/
|
||||
public List<OidcSession> getAllByTarget(Long clientId) {
|
||||
return Lists.newArrayList(oidcSessionRepository.findAll(qOidcSession.client.eq(clientId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the all by subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the all by subject
|
||||
*/
|
||||
public List<OidcSession> getAllBySubject(Long subject) {
|
||||
return Lists.newArrayList(oidcSessionRepository.findAll(qOidcSession.subject.eq(subject)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the all by target and subject.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @return the all by target and subject
|
||||
*/
|
||||
public List<OidcSession> getAllByTargetAndSubject(Long clientId, Long subject) {
|
||||
return Lists.newArrayList(
|
||||
oidcSessionRepository.findAll(qOidcSession.client.eq(clientId).and(qOidcSession.subject.eq(subject))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete.
|
||||
*
|
||||
* @param session the session
|
||||
*/
|
||||
public void delete(OidcSession session) {
|
||||
if (oidcSessionRepository.existsById(session.getId())) {
|
||||
oidcSessionRepository.delete(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete by sid.
|
||||
*
|
||||
* @param sid the sid
|
||||
*/
|
||||
public void deleteBySid(String sid) {
|
||||
OidcSession session = getBySid(sid);
|
||||
if (session != null) {
|
||||
delete(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete by id token.
|
||||
*
|
||||
* @param idToken the id token
|
||||
*/
|
||||
public void deleteByIdToken(String idToken) {
|
||||
OidcSession session = getByIdToken(idToken);
|
||||
if (session != null) {
|
||||
delete(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all by spring session.
|
||||
*
|
||||
* @param springSession the spring session
|
||||
*/
|
||||
public void deleteAllBySpringSession(String springSession) {
|
||||
for (OidcSession token : getAllBySpringSession(springSession)) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all by target.
|
||||
*
|
||||
* @param target the target
|
||||
*/
|
||||
public void deleteAllByTarget(Long target) {
|
||||
for (OidcSession token : getAllByTarget(target)) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all by subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
*/
|
||||
public void deleteAllBySubject(Long subject) {
|
||||
for (OidcSession token : getAllBySubject(subject)) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backchannel logout.
|
||||
*
|
||||
* @param sid the sid
|
||||
* @param issuer the issuer
|
||||
*/
|
||||
public void backchannelLogout(String sid, String issuer) {
|
||||
OidcSession session = getBySid(sid);
|
||||
Assert.notNull(session, "invalid sid!");
|
||||
OidcClient client = oidcRegisteredClientManager.get(session.getClientId());
|
||||
if (client == null) {
|
||||
logger.error("OidcSession '" + session.getId() + "' (subject: " + session.getSubject()
|
||||
+ ") with invalid OidcRegisteredClient: " + session.getClientId());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
sendBackchannelLogout(session.getSubject(), sid, issuer, client);
|
||||
oidcSessionRepository.delete(session);
|
||||
} catch (JOSEException e) {
|
||||
logger.warn("JOSEException on backchannelLogout!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backchannel logout.
|
||||
*
|
||||
* @param clientId the client id
|
||||
* @param subject the subject
|
||||
* @param issuer the issuer
|
||||
*/
|
||||
public void backchannelLogout(Long clientId, Long subject, String issuer) {
|
||||
List<OidcSession> sessions = getAllByTargetAndSubject(clientId, subject);
|
||||
|
||||
if (!sessions.isEmpty()) {
|
||||
OidcSession session = sessions.get(0);
|
||||
OidcClient client = oidcRegisteredClientManager.get(session.getClientId());
|
||||
if (client != null) {
|
||||
try {
|
||||
sendBackchannelLogout(subject, null, issuer, client);
|
||||
} catch (JOSEException e) {
|
||||
logger.warn("JOSEException on backchannelLogout!", e);
|
||||
}
|
||||
} else {
|
||||
logger.error("OidcSession '" + session.getId() + "' (subject: " + session.getSubject()
|
||||
+ ") with invalid OidcRegisteredClient: " + session.getClientId());
|
||||
}
|
||||
|
||||
oidcSessionRepository.deleteAll(sessions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backchannel logout.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @param issuer the issuer
|
||||
*/
|
||||
public void backchannelLogout(Long subject, String issuer) {
|
||||
Set<Long> clients = Sets.newHashSet();
|
||||
for (OidcSession session : getAllBySubject(subject)) {
|
||||
OidcClient client = oidcRegisteredClientManager.get(session.getClientId());
|
||||
if (client == null) {
|
||||
logger.error("OidcSession '" + session.getId() + "' (subject: " + session.getSubject()
|
||||
+ ") with invalid OidcRegisteredClient: " + session.getClientId());
|
||||
continue;
|
||||
}
|
||||
if (!clients.contains(client.getId())) {
|
||||
try {
|
||||
sendBackchannelLogout(subject, null, issuer, client);
|
||||
clients.add(client.getId());
|
||||
} catch (JOSEException e) {
|
||||
logger.warn("JOSEException on backchannelLogout!", e);
|
||||
}
|
||||
}
|
||||
oidcSessionRepository.delete(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backchannel logout spring.
|
||||
*
|
||||
* @param springSessionId the spring session id
|
||||
* @param issuer the issuer
|
||||
*/
|
||||
public void backchannelLogoutSpring(String springSessionId, String issuer) {
|
||||
for (OidcSession session : getAllBySpringSession(springSessionId)) {
|
||||
OidcClient client = oidcRegisteredClientManager.get(session.getClientId());
|
||||
if (client == null) {
|
||||
logger.error("OidcSession '" + session.getId() + "' (subject: " + session.getSubject()
|
||||
+ ") with invalid OidcRegisteredClient: " + session.getClientId());
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
sendBackchannelLogout(session.getSubject(), session.getSid(), issuer, client);
|
||||
oidcSessionRepository.delete(session);
|
||||
} catch (JOSEException e) {
|
||||
logger.warn("JOSEException on backchannelLogout!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send backchannel logout.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @param sid the sid
|
||||
* @param issuer the issuer
|
||||
* @param client the client
|
||||
* @throws JOSEException the JOSE exception
|
||||
*/
|
||||
// @Async("threadPoolTaskExecutor")
|
||||
public void sendBackchannelLogout(Long subject, String sid, String issuer, OidcClient client) throws JOSEException {
|
||||
|
||||
if (!StringUtils.hasText(client.getBackchannelLogoutUri())) {
|
||||
logger.warn("Could not send backchannel logout for '" + subject
|
||||
+ "' without backchannel_logout_uri of OidcRegisteredClient '" + client.getId()
|
||||
+ "' not possible!");
|
||||
return;
|
||||
}
|
||||
|
||||
SignedJWT logoutToken = createBackchannelLogoutToken(subject, sid, issuer, client);
|
||||
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
formData.add("logout_token", logoutToken.serialize());
|
||||
ResponseEntity<?> response = null;
|
||||
try {
|
||||
response = webClient.method(HttpMethod.POST).uri(client.getBackchannelLogoutUri())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED).body(BodyInserters.fromFormData(formData))
|
||||
.retrieve().onStatus(HttpStatus::isError, error -> Mono.empty()).toBodilessEntity().block();
|
||||
} catch (Exception e) {
|
||||
logger.warn("backchannelLogout POST '" + client.getBackchannelLogoutUri() + "' failed", e);
|
||||
}
|
||||
|
||||
if (response != null && !response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
logger.info("backchannelLogout for '" + subject + "' failed with status: " + response.getStatusCode()
|
||||
+ " from " + client.getBackchannelLogoutUri() + "(client: " + client.getId() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the backchannel logout token.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @param sid the sid
|
||||
* @param issuer the issuer
|
||||
* @param client the client
|
||||
* @return the signed JWT
|
||||
* @throws JOSEException the JOSE exception
|
||||
*/
|
||||
protected SignedJWT createBackchannelLogoutToken(Long subject, String sid, String issuer, OidcClient client)
|
||||
throws JOSEException {
|
||||
if (!StringUtils.hasText(client.getBackchannelLogoutUri())) {
|
||||
logger.warn("Creation of logout token '" + subject
|
||||
+ "' without backchannel_logout_uri of OidcRegisteredClient '" + client.getId()
|
||||
+ "' not possible!");
|
||||
return null;
|
||||
}
|
||||
|
||||
JWTClaimsSet.Builder claimsSetBuilder = new JWTClaimsSet.Builder();
|
||||
|
||||
claimsSetBuilder.subject(String.valueOf(subject));
|
||||
claimsSetBuilder.issuer(issuer);
|
||||
claimsSetBuilder.audience(client.getClientId());
|
||||
claimsSetBuilder.issueTime(new Date());
|
||||
claimsSetBuilder.jwtID(RandomStringUtils.random(JWT_ID_LENGTH, true, true));
|
||||
if (StringUtils.hasText(sid)) {
|
||||
claimsSetBuilder.claim("sid", sid);
|
||||
}
|
||||
|
||||
Map<String, Object> events = Maps.newHashMap();
|
||||
events.put("http://schemas.openid.net/event/backchannel-logout", Maps.newHashMap());
|
||||
claimsSetBuilder.claim("events", events);
|
||||
|
||||
JwtKey jwtKey = jwtKeyManager.getLatest(OidcTokenManager.OIDC_JWT_KEY_NAME, false);
|
||||
|
||||
if (jwtKey == null) {
|
||||
throw new JOSEException("No jwtKey found!");
|
||||
}
|
||||
|
||||
JWK jwk = jwtKeyManager.parseKey(jwtKey);
|
||||
|
||||
JWSSigner jwsSigner = jwtKeyManager.createSigner(jwtKey);
|
||||
|
||||
if (jwsSigner == null) {
|
||||
throw new JOSEException("Signer could not be created!");
|
||||
}
|
||||
|
||||
JWSAlgorithm algorithm = jwtKeyManager.getJwsAlgorithm(jwtKey);
|
||||
|
||||
if (algorithm == null) {
|
||||
algorithm = JWSAlgorithm.HS512;
|
||||
}
|
||||
|
||||
JWSHeader.Builder headerBuilder = new JWSHeader.Builder(algorithm);
|
||||
|
||||
headerBuilder.keyID(jwk.getKeyID());
|
||||
|
||||
SignedJWT jwt = new SignedJWT(headerBuilder.build(), claimsSetBuilder.build());
|
||||
jwt.sign(jwsSigner);
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
}
|
@ -7,26 +7,35 @@ import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.beust.jcommander.internal.Maps;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JOSEObjectType;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.KeyType;
|
||||
import com.nimbusds.jose.jwk.KeyUse;
|
||||
import com.nimbusds.jwt.JWTClaimsSet.Builder;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
|
||||
import de.bstly.we.businesslogic.PermissionManager;
|
||||
import de.bstly.we.businesslogic.QuotaManager;
|
||||
@ -39,6 +48,7 @@ import de.bstly.we.model.Permission;
|
||||
import de.bstly.we.model.Quota;
|
||||
import de.bstly.we.model.User;
|
||||
import de.bstly.we.model.UserProfileField;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcToken;
|
||||
import de.bstly.we.oidc.model.QOidcToken;
|
||||
@ -50,12 +60,16 @@ import de.bstly.we.oidc.repository.OidcTokenRepository;
|
||||
@Service
|
||||
public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(OidcTokenManager.class);
|
||||
|
||||
public static final int ACCESS_TOKEN_LENGTH = 64;
|
||||
public static final int REFRESH_TOKEN_LENGTH = 64;
|
||||
|
||||
public static final String OIDC_JWT_KEY_NAME = "oidc";
|
||||
public static final String BEARER_TOKEN_TYPE = "Bearer";
|
||||
|
||||
@Autowired
|
||||
private OidcTokenRepository tokenRepository;
|
||||
private OidcTokenRepository oidcTokenRepository;
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
@ -104,11 +118,40 @@ public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
* @return the oidc token
|
||||
*/
|
||||
public OidcToken createToken(OidcClient client, Long userId) {
|
||||
return createToken(client, userId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the token.
|
||||
*
|
||||
* @param client the client
|
||||
* @param userId the user id
|
||||
* @param refreshToken the refresh token
|
||||
* @return the oidc token
|
||||
*/
|
||||
public OidcToken createToken(OidcClient client, Long userId, boolean refreshToken) {
|
||||
return createToken(client, userId,
|
||||
refreshToken ? RandomStringUtils.random(REFRESH_TOKEN_LENGTH, true, true) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the token.
|
||||
*
|
||||
* @param client the client
|
||||
* @param userId the user id
|
||||
* @param refreshToken the refresh token
|
||||
* @return the oidc token
|
||||
*/
|
||||
public OidcToken createToken(OidcClient client, Long userId, String refreshToken) {
|
||||
OidcToken token = new OidcToken();
|
||||
token.setUserId(userId);
|
||||
token.setAccessToken(RandomStringUtils.random(ACCESS_TOKEN_LENGTH, true, true));
|
||||
if (StringUtils.hasText(refreshToken)) {
|
||||
token.setRefreshToken(refreshToken);
|
||||
}
|
||||
token.setExpiresIn(client.getTokenLifetime());
|
||||
return tokenRepository.save(token);
|
||||
token.setCreated(Instant.now());
|
||||
return oidcTokenRepository.save(token);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,18 +162,18 @@ public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
* @param nonce the nonce
|
||||
* @param scopes the scopes
|
||||
* @param issuer the issuer
|
||||
* @param sid the sid
|
||||
* @return the oidc token
|
||||
* @throws JOSEException the JOSE exception
|
||||
*/
|
||||
public OidcToken createTokenWithIdToken(OidcClient client, Long userId, String nonce, Set<String> scopes,
|
||||
String issuer) throws JOSEException {
|
||||
OidcToken token = new OidcToken();
|
||||
token.setClient(client.getId());
|
||||
|
||||
String issuer, String sid) throws JOSEException {
|
||||
User user = userManager.get(userId);
|
||||
|
||||
Assert.notNull(user, "User does not exist!");
|
||||
|
||||
OidcToken token = createToken(client, client.getId(),
|
||||
client.getAuthorizationGrantTypes().contains(OidcAuthorizationGrantType.refresh_token));
|
||||
|
||||
token.setUserId(user.getId());
|
||||
token.setAccessToken(RandomStringUtils.random(ACCESS_TOKEN_LENGTH, true, true));
|
||||
token.setExpiresIn(client.getTokenLifetime());
|
||||
@ -147,6 +190,10 @@ public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
claimsSetBuilder.claim("nonce", nonce);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(sid)) {
|
||||
claimsSetBuilder.claim("sid", sid);
|
||||
}
|
||||
|
||||
JwtKey jwtKey = jwtKeyManager.getLatest(OIDC_JWT_KEY_NAME, false);
|
||||
|
||||
if (jwtKey == null) {
|
||||
@ -162,7 +209,7 @@ public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
|
||||
token.setIdToken(jwt.serialize());
|
||||
|
||||
return tokenRepository.save(token);
|
||||
return oidcTokenRepository.save(token);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,15 +281,112 @@ public class OidcTokenManager implements SmartInitializingSingleton {
|
||||
* @return the by access token
|
||||
*/
|
||||
public OidcToken getByAccessToken(String accessToken) {
|
||||
return tokenRepository.findOne(qOidcToken.accessToken.eq(accessToken)).orElse(null);
|
||||
return oidcTokenRepository.findOne(qOidcToken.accessToken.eq(accessToken)).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the jwk set.
|
||||
* Gets the last by refresh token.
|
||||
*
|
||||
* @return the jwk set
|
||||
* @param refreshToken the refresh token
|
||||
* @return the last by refresh token
|
||||
*/
|
||||
public JWKSet getJwkSet() {
|
||||
return jwtKeyManager.getJwkSet(OIDC_JWT_KEY_NAME, false);
|
||||
public OidcToken getLastByRefreshToken(String refreshToken) {
|
||||
List<OidcToken> token = getAllByRefreshToken(refreshToken);
|
||||
if (token.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return token.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the all by refresh token.
|
||||
*
|
||||
* @param refreshToken the refresh token
|
||||
* @return the all by refresh token
|
||||
*/
|
||||
public List<OidcToken> getAllByRefreshToken(String refreshToken) {
|
||||
return Lists.newArrayList(oidcTokenRepository.findAll(qOidcToken.refreshToken.eq(refreshToken),
|
||||
Sort.by(Sort.Direction.DESC, "created")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete.
|
||||
*
|
||||
* @param token the token
|
||||
*/
|
||||
public void delete(OidcToken token) {
|
||||
if (oidcTokenRepository.existsById(token.getId())) {
|
||||
oidcTokenRepository.delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete by access token.
|
||||
*
|
||||
* @param accessToken the access token
|
||||
*/
|
||||
public void deleteByAccessToken(String accessToken) {
|
||||
OidcToken token = getByAccessToken(accessToken);
|
||||
if (token != null) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all by refresh token.
|
||||
*
|
||||
* @param refreshToken the refresh token
|
||||
*/
|
||||
public void deleteAllByRefreshToken(String refreshToken) {
|
||||
for (OidcToken token : oidcTokenRepository.findAll(qOidcToken.refreshToken.eq(refreshToken))) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all by target.
|
||||
*
|
||||
* @param userId the user id
|
||||
*/
|
||||
public void deleteAllByTarget(Long userId) {
|
||||
for (OidcToken token : oidcTokenRepository.findAll(qOidcToken.userId.eq(userId))) {
|
||||
delete(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron.
|
||||
*/
|
||||
@Scheduled(cron = "${openid-provider.token.cleanup.cron:0 0 0,12 * * * }")
|
||||
public void cron() {
|
||||
deleteExpired(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete expired.
|
||||
*
|
||||
* @param includeRefreshToken the include refresh token
|
||||
*/
|
||||
public void deleteExpired(boolean includeRefreshToken) {
|
||||
BooleanBuilder predicate = new BooleanBuilder();
|
||||
predicate.and(qOidcToken.expiresIn.gt(0L));
|
||||
if (!includeRefreshToken) {
|
||||
predicate.and(qOidcToken.refreshToken.isEmpty().or(qOidcToken.refreshToken.isNull()));
|
||||
}
|
||||
Pageable pageable = PageRequest.of(0, 500, Sort.by("id"));
|
||||
Page<OidcToken> page;
|
||||
do {
|
||||
page = oidcTokenRepository.findAll(predicate.getValue(), pageable);
|
||||
for (OidcToken oidcToken : page.getContent()) {
|
||||
if (oidcToken.getCreated()
|
||||
.isBefore(Instant.now().minus(oidcToken.getExpiresIn(), ChronoUnit.SECONDS))) {
|
||||
logger.debug(
|
||||
"delete expired OidcToken: " + oidcToken.getId() + " [" + oidcToken.getAccessToken() + "]");
|
||||
delete(oidcToken);
|
||||
}
|
||||
}
|
||||
pageable = page.nextPageable();
|
||||
} while (page.hasNext());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,113 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic.exception;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationErrorCode;
|
||||
|
||||
/**
|
||||
* The Class InvalidAuthorizationRequestException.
|
||||
*/
|
||||
public class InvalidAuthorizationRequestException extends RuntimeException {
|
||||
/**
|
||||
* default serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private URI redirectUri;
|
||||
private OidcAuthorizationErrorCode errorCode;
|
||||
private String errorDescription;
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* Instantiates a new invalid authorization request exception.
|
||||
*
|
||||
* @param redirectUri the redirect uri
|
||||
* @param errorCode the error code
|
||||
* @param errorDescription the error description
|
||||
* @param state the state
|
||||
*/
|
||||
public InvalidAuthorizationRequestException(URI redirectUri, OidcAuthorizationErrorCode errorCode,
|
||||
String errorDescription, String state) {
|
||||
super(errorDescription);
|
||||
this.redirectUri = redirectUri;
|
||||
this.errorCode = errorCode;
|
||||
this.errorDescription = errorDescription;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redirect uri.
|
||||
*
|
||||
* @return the redirect uri
|
||||
*/
|
||||
public URI getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the redirect uri.
|
||||
*
|
||||
* @param redirectUri the new redirect uri
|
||||
*/
|
||||
public void setRedirectUri(URI redirectUri) {
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public OidcAuthorizationErrorCode getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error code.
|
||||
*
|
||||
* @param errorCode the new error code
|
||||
*/
|
||||
public void setErrorCode(OidcAuthorizationErrorCode errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public String getErrorDescription() {
|
||||
return errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error description.
|
||||
*
|
||||
* @param errorDescription the new error description
|
||||
*/
|
||||
public void setErrorDescription(String errorDescription) {
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state.
|
||||
*
|
||||
* @param state the new state
|
||||
*/
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic.exception;
|
||||
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcTokenErrorCode;
|
||||
|
||||
/**
|
||||
* The Class InvalidTokenRequestException.
|
||||
*/
|
||||
public class InvalidTokenRequestException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* default serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private OidcTokenErrorCode errorCode;
|
||||
private String errorDescription;
|
||||
|
||||
/**
|
||||
* Instantiates a new invalid token request exception.
|
||||
*
|
||||
* @param errorCode the error code
|
||||
* @param errorDescription the error description
|
||||
*/
|
||||
public InvalidTokenRequestException(OidcTokenErrorCode errorCode, String errorDescription) {
|
||||
super(errorDescription);
|
||||
this.errorCode = errorCode;
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public OidcTokenErrorCode getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error code.
|
||||
*
|
||||
* @param errorCode the new error code
|
||||
*/
|
||||
public void setErrorCode(OidcTokenErrorCode errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public String getErrorDescription() {
|
||||
return errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error description.
|
||||
*
|
||||
* @param errorDescription the new error description
|
||||
*/
|
||||
public void setErrorDescription(String errorDescription) {
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
@ -25,6 +25,7 @@ public class OidcAuthorizationCode {
|
||||
private final Instant expiry;
|
||||
private final Long userId;
|
||||
private final String nonce;
|
||||
private String springSession;
|
||||
|
||||
/**
|
||||
* Instantiates a new oidc authorization code.
|
||||
@ -108,4 +109,22 @@ public class OidcAuthorizationCode {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the spring session.
|
||||
*
|
||||
* @return the spring session
|
||||
*/
|
||||
public String getSpringSession() {
|
||||
return springSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the spring session.
|
||||
*
|
||||
* @param springSession the new spring session
|
||||
*/
|
||||
public void setSpringSession(String springSession) {
|
||||
this.springSession = springSession;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcAuthorizationErrorCode.
|
@ -1,11 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcAuthorizationGrantType.
|
||||
*/
|
||||
public enum OidcAuthorizationGrantType {
|
||||
authorization_code, client_credentials
|
||||
authorization_code, client_credentials, refresh_token
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* The Class OidcAuthorizationRequest.
|
||||
*/
|
||||
public class OidcAuthorizationRequest {
|
||||
|
||||
private String code;
|
||||
private final String client_id;
|
||||
private final String response_type;
|
||||
private final URI redirect_uri;
|
||||
private final String scope;
|
||||
private String state;
|
||||
private String nonce;
|
||||
private String display;
|
||||
private String prompt;
|
||||
private String max_age;
|
||||
private String ui_locales;
|
||||
private String id_token_hint;
|
||||
private String login_hint;
|
||||
private String acr_values;
|
||||
|
||||
/**
|
||||
* Instantiates a new oidc authorization request.
|
||||
*
|
||||
* @param code the code
|
||||
* @param client_id the client id
|
||||
* @param response_type the response type
|
||||
* @param redirect_uri the redirect uri
|
||||
* @param scope the scope
|
||||
* @param state the state
|
||||
* @param nonce the nonce
|
||||
* @param display the display
|
||||
* @param prompt the prompt
|
||||
* @param max_age the max age
|
||||
* @param ui_locales the ui locales
|
||||
* @param id_token_hint the id token hint
|
||||
* @param login_hint the login hint
|
||||
* @param acr_values the acr values
|
||||
*/
|
||||
public OidcAuthorizationRequest(String code, String client_id, String response_type, URI redirect_uri, String scope,
|
||||
String state, String nonce, String display, String prompt, String max_age, String ui_locales,
|
||||
String id_token_hint, String login_hint, String acr_values) {
|
||||
super();
|
||||
this.code = code;
|
||||
this.client_id = client_id;
|
||||
this.response_type = response_type;
|
||||
this.redirect_uri = redirect_uri;
|
||||
this.scope = scope;
|
||||
this.state = state;
|
||||
this.nonce = nonce;
|
||||
this.display = display;
|
||||
this.prompt = prompt;
|
||||
this.max_age = max_age;
|
||||
this.ui_locales = ui_locales;
|
||||
this.id_token_hint = id_token_hint;
|
||||
this.login_hint = login_hint;
|
||||
this.acr_values = acr_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the code.
|
||||
*
|
||||
* @return the code
|
||||
*/
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the code.
|
||||
*
|
||||
* @param code the new code
|
||||
*/
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client id.
|
||||
*
|
||||
* @return the client id
|
||||
*/
|
||||
public String getClient_id() {
|
||||
return client_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response type.
|
||||
*
|
||||
* @return the response type
|
||||
*/
|
||||
public String getResponse_type() {
|
||||
return response_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redirect uri.
|
||||
*
|
||||
* @return the redirect uri
|
||||
*/
|
||||
public URI getRedirect_uri() {
|
||||
return redirect_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scope.
|
||||
*
|
||||
* @return the scope
|
||||
*/
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state.
|
||||
*
|
||||
* @param state the new state
|
||||
*/
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display.
|
||||
*
|
||||
* @return the display
|
||||
*/
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display.
|
||||
*
|
||||
* @param display the new display
|
||||
*/
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nonce.
|
||||
*
|
||||
* @return the nonce
|
||||
*/
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the nonce.
|
||||
*
|
||||
* @param nonce the new nonce
|
||||
*/
|
||||
public void setNonce(String nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the prompt.
|
||||
*
|
||||
* @return the prompt
|
||||
*/
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prompt.
|
||||
*
|
||||
* @param prompt the new prompt
|
||||
*/
|
||||
public void setPrompt(String prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max age.
|
||||
*
|
||||
* @return the max age
|
||||
*/
|
||||
public String getMax_age() {
|
||||
return max_age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max age.
|
||||
*
|
||||
* @param max_age the new max age
|
||||
*/
|
||||
public void setMax_age(String max_age) {
|
||||
this.max_age = max_age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ui locales.
|
||||
*
|
||||
* @return the ui locales
|
||||
*/
|
||||
public String getUi_locales() {
|
||||
return ui_locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ui locales.
|
||||
*
|
||||
* @param ui_locales the new ui locales
|
||||
*/
|
||||
public void setUi_locales(String ui_locales) {
|
||||
this.ui_locales = ui_locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id token hint.
|
||||
*
|
||||
* @return the id token hint
|
||||
*/
|
||||
public String getId_token_hint() {
|
||||
return id_token_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id token hint.
|
||||
*
|
||||
* @param id_token_hint the new id token hint
|
||||
*/
|
||||
public void setId_token_hint(String id_token_hint) {
|
||||
this.id_token_hint = id_token_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login hint.
|
||||
*
|
||||
* @return the login hint
|
||||
*/
|
||||
public String getLogin_hint() {
|
||||
return login_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the login hint.
|
||||
*
|
||||
* @param login_hint the new login hint
|
||||
*/
|
||||
public void setLogin_hint(String login_hint) {
|
||||
this.login_hint = login_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the acr values.
|
||||
*
|
||||
* @return the acr values
|
||||
*/
|
||||
public String getAcr_values() {
|
||||
return acr_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the acr values.
|
||||
*
|
||||
* @param acr_values the new acr values
|
||||
*/
|
||||
public void setAcr_values(String acr_values) {
|
||||
this.acr_values = acr_values;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcAuthorizationResponseType.
|
||||
*/
|
||||
public enum OidcAuthorizationResponseType {
|
||||
AUTHORIZATION_CODE("code");
|
||||
|
||||
private final String authorizationResponseType;
|
||||
|
||||
/**
|
||||
* Instantiates a new oidc authorization response type.
|
||||
*
|
||||
* @param authorizationGrantType the authorization grant type
|
||||
*/
|
||||
OidcAuthorizationResponseType(String authorizationGrantType) {
|
||||
this.authorizationResponseType = authorizationGrantType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authorization response type.
|
||||
*
|
||||
* @return the authorization response type
|
||||
*/
|
||||
public String getAuthorizationResponseType() {
|
||||
return authorizationResponseType;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcClientAuthenticationMethod.
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcTokenErrorCode.
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@ -14,6 +14,7 @@ public class OidcTokenRequest {
|
||||
private final OidcAuthorizationGrantType grant_type;
|
||||
private String client_id;
|
||||
private String client_secret;
|
||||
private String refresh_token;
|
||||
private final URI redirect_uri;
|
||||
private final String scope;
|
||||
|
||||
@ -24,16 +25,18 @@ public class OidcTokenRequest {
|
||||
* @param grant_type the grant type
|
||||
* @param client_id the client id
|
||||
* @param client_secret the client secret
|
||||
* @param refresh_token the refresh token
|
||||
* @param redirect_uri the redirect uri
|
||||
* @param scope the scope
|
||||
*/
|
||||
public OidcTokenRequest(String code, OidcAuthorizationGrantType grant_type, String client_id, String client_secret,
|
||||
URI redirect_uri, String scope) {
|
||||
String refresh_token, URI redirect_uri, String scope) {
|
||||
super();
|
||||
this.code = code;
|
||||
this.grant_type = grant_type;
|
||||
this.client_id = client_id;
|
||||
this.client_secret = client_secret;
|
||||
this.refresh_token = refresh_token;
|
||||
this.redirect_uri = redirect_uri;
|
||||
this.scope = scope;
|
||||
}
|
||||
@ -74,6 +77,24 @@ public class OidcTokenRequest {
|
||||
this.client_secret = client_secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the refresh token.
|
||||
*
|
||||
* @return the refresh token
|
||||
*/
|
||||
public String getRefresh_token() {
|
||||
return refresh_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the refresh token.
|
||||
*
|
||||
* @param refresh_token the new refresh token
|
||||
*/
|
||||
public void setRefresh_token(String refresh_token) {
|
||||
this.refresh_token = refresh_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the code.
|
||||
*
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Class OidcTokenResponse.
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.businesslogic.model;
|
||||
|
||||
/**
|
||||
* The Class OidcTokenRevokeRequest.
|
||||
*/
|
||||
public class OidcTokenRevokeRequest {
|
||||
|
||||
private String token;
|
||||
private String token_type_hint;
|
||||
|
||||
/**
|
||||
* Gets the token.
|
||||
*
|
||||
* @return the token
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token.
|
||||
*
|
||||
* @param token the new token
|
||||
*/
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token type hint.
|
||||
*
|
||||
* @return the token type hint
|
||||
*/
|
||||
public String getToken_type_hint() {
|
||||
return token_type_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token type hint.
|
||||
*
|
||||
* @param token_type_hint the new token type hint
|
||||
*/
|
||||
public void setToken_type_hint(String token_type_hint) {
|
||||
this.token_type_hint = token_type_hint;
|
||||
}
|
||||
|
||||
}
|
@ -24,10 +24,10 @@ import com.google.common.collect.Sets;
|
||||
import de.bstly.we.controller.BaseController;
|
||||
import de.bstly.we.controller.support.EntityResponseStatusException;
|
||||
import de.bstly.we.oidc.businesslogic.OidcClientManager;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.controller.model.OidcClientModel;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.repository.OidcClientRepository;
|
||||
|
||||
/**
|
||||
|
@ -13,25 +13,31 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.bstly.we.businesslogic.PermissionManager;
|
||||
import de.bstly.we.businesslogic.Permissions;
|
||||
import de.bstly.we.oidc.businesslogic.OidcAuthorizationCodeManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcAuthorizationManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcClientManager;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationErrorCode;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationResponseType;
|
||||
import de.bstly.we.oidc.businesslogic.exception.InvalidAuthorizationRequestException;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationErrorCode;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationRequest;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationResponseType;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.security.model.LocalUserDetails;
|
||||
|
||||
@ -49,7 +55,10 @@ public class OidcAuthorizationController {
|
||||
@Autowired
|
||||
private OidcClientManager oidcClientManager;
|
||||
@Autowired
|
||||
private OidcAuthorizationCodeManager oidcAuthorizationCodeManager;
|
||||
private OidcAuthorizationManager oidcAuthorizationManager;
|
||||
|
||||
@Value("${oidcAuthorizationFormUrl:/oidc/authorize/form}")
|
||||
private String authorizationFormUrl;
|
||||
|
||||
/**
|
||||
* Authorization request.
|
||||
@ -60,36 +69,21 @@ public class OidcAuthorizationController {
|
||||
* @param redirectUri the redirect uri
|
||||
* @param state the state
|
||||
* @param nonce the nonce
|
||||
* @param prompt the prompt
|
||||
* @param login_hint the login hint
|
||||
* @param code the code
|
||||
* @param principal the principal
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping
|
||||
void authorizationRequest(
|
||||
// for OIDC scope must contain "openid"
|
||||
@RequestParam(name = "scope") String scope,
|
||||
// for now only "code" is available
|
||||
@RequestParam(name = "response_type") String responseType,
|
||||
// client id
|
||||
@RequestParam(name = "client_id") String clientId,
|
||||
// redirect url
|
||||
@RequestParam(name = "redirect_uri") URI redirectUri,
|
||||
// optional state
|
||||
@RequestParam(name = "state", required = false) String state,
|
||||
// optional state
|
||||
@RequestParam(name = "nonce", required = false) String nonce,
|
||||
// authentication details
|
||||
@AuthenticationPrincipal LocalUserDetails principal,
|
||||
// the request
|
||||
HttpServletRequest request,
|
||||
// the response
|
||||
HttpServletResponse response) throws IOException {
|
||||
protected void authorizationRequest(String scope, String responseType, String clientId, URI redirectUri,
|
||||
String state, String nonce, String prompt, String login_hint, String code, LocalUserDetails principal,
|
||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
|
||||
if (!StringUtils.hasText(clientId)) {
|
||||
logger.debug("missing client_id");
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
"missing client_id", state);
|
||||
}
|
||||
|
||||
@ -97,14 +91,14 @@ public class OidcAuthorizationController {
|
||||
|
||||
if (client == null) {
|
||||
logger.debug("invalid client_id: " + clientId);
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
"invalid client_id", state);
|
||||
|
||||
}
|
||||
|
||||
if (!client.getRedirectUris().contains(redirectUri.toString())) {
|
||||
logger.debug("invalid redirect_uri: " + redirectUri + " allowed: " + client.getRedirectUris());
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
"invalid redirect_uri", state);
|
||||
}
|
||||
|
||||
@ -112,23 +106,22 @@ public class OidcAuthorizationController {
|
||||
&& !permissionManager.hasPermission(principal.getUserId(), client.getClientName())
|
||||
&& !permissionManager.hasPermission(principal.getUserId(), Permissions.ROLE_ADMIN)) {
|
||||
logger.debug("user not allowed: " + principal.getUserId() + " - " + client.getClientName());
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.ACCESS_DENIED,
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.ACCESS_DENIED,
|
||||
"user not allowed", state);
|
||||
}
|
||||
|
||||
if (!client.getAuthorizationGrantTypes().contains(OidcAuthorizationGrantType.authorization_code)) {
|
||||
logger.debug("authorization grant type not allowed: " + OidcAuthorizationGrantType.authorization_code
|
||||
+ " - " + client.getClientName());
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.UNAUTHORIZED_CLIENT,
|
||||
"authorization grant type not allowed", state);
|
||||
|
||||
throw new InvalidAuthorizationRequestException(redirectUri,
|
||||
OidcAuthorizationErrorCode.INVALID_REQUEST_OBJECT, "authorization grant type not allowed", state);
|
||||
}
|
||||
|
||||
if (!responseType.equals(OidcAuthorizationResponseType.code.toString())) {
|
||||
logger.debug("response type not allowed: " + OidcAuthorizationResponseType.code
|
||||
|
||||
+ " - " + client.getClientName());
|
||||
throw new InvalidAuthorizationRequestError(redirectUri,
|
||||
if (!responseType.equals(OidcAuthorizationResponseType.AUTHORIZATION_CODE.getAuthorizationResponseType())) {
|
||||
logger.debug("response type not allowed: "
|
||||
+ OidcAuthorizationResponseType.AUTHORIZATION_CODE.getAuthorizationResponseType() + " - "
|
||||
+ client.getClientName());
|
||||
throw new InvalidAuthorizationRequestException(redirectUri,
|
||||
OidcAuthorizationErrorCode.UNSUPPORTED_RESPONSE_TYPE, "response type not allowed", state);
|
||||
|
||||
}
|
||||
@ -137,27 +130,151 @@ public class OidcAuthorizationController {
|
||||
|
||||
if (!scopes.contains("openid")) {
|
||||
logger.debug("missing openid scope: " + scopes + " - " + client.getClientName());
|
||||
throw new InvalidAuthorizationRequestError(redirectUri, OidcAuthorizationErrorCode.INVALID_SCOPE,
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_SCOPE,
|
||||
"missing openid scope", state);
|
||||
|
||||
}
|
||||
|
||||
OidcAuthorizationCode authorizationCode = oidcAuthorizationCodeManager.create(clientId, redirectUri, scopes,
|
||||
principal.getUserId(), nonce);
|
||||
if (!client.getScopes().containsAll(scopes)) {
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_SCOPE,
|
||||
"some scopes not allowed", state);
|
||||
}
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUri(redirectUri);
|
||||
|
||||
String uri = redirectUri.toString();
|
||||
Set<String> prompts = Sets.newHashSet();
|
||||
|
||||
if (StringUtils.hasText(redirectUri.getQuery())) {
|
||||
uri += "&code=" + authorizationCode.getCode();
|
||||
if (StringUtils.hasText(prompt)) {
|
||||
prompts = Sets.newHashSet(prompt.split(" "));
|
||||
}
|
||||
|
||||
if (prompts.contains("none") && prompts.size() > 1) {
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INVALID_REQUEST,
|
||||
"prompt contains more than 'none'", state);
|
||||
} else if (prompts.contains("none") && client.isAuthorize()
|
||||
&& !oidcAuthorizationManager.isAuthorized(client.getId(), principal.getUserId(), scopes)) {
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.INTERACTION_REQUIRED,
|
||||
"prompt 'consent' required beforehand", state);
|
||||
}
|
||||
|
||||
OidcAuthorizationCode authorizationCode;
|
||||
|
||||
if (StringUtils.hasText(code)) {
|
||||
authorizationCode = oidcAuthorizationManager.getCode(code);
|
||||
if (authorizationCode == null) {
|
||||
throw new InvalidAuthorizationRequestException(redirectUri,
|
||||
OidcAuthorizationErrorCode.INVALID_REQUEST_OBJECT, "invalid code", state);
|
||||
}
|
||||
|
||||
if (!authorizationCode.getUserId().equals(principal.getUserId())) {
|
||||
throw new InvalidAuthorizationRequestException(redirectUri, OidcAuthorizationErrorCode.LOGIN_REQUIRED,
|
||||
"code does not match user", state);
|
||||
}
|
||||
|
||||
oidcAuthorizationManager.authorize(client.getId(), principal.getUserId(), scopes);
|
||||
} else {
|
||||
uri += "?code=" + authorizationCode.getCode();
|
||||
if (client.isAuthorize()
|
||||
&& !oidcAuthorizationManager.isAuthorized(client.getId(), principal.getUserId(), scopes)
|
||||
|| prompts.contains("consent")) {
|
||||
uriBuilder = UriComponentsBuilder.fromUriString(authorizationFormUrl);
|
||||
uriBuilder.queryParam("client_id", clientId);
|
||||
uriBuilder.queryParam("response_type", responseType);
|
||||
uriBuilder.queryParam("redirect_uri", redirectUri);
|
||||
uriBuilder.queryParam("scope", scope);
|
||||
|
||||
if (StringUtils.hasText(nonce)) {
|
||||
uriBuilder.queryParam("nonce", nonce);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(prompt)) {
|
||||
uriBuilder.queryParam("prompt", prompt);
|
||||
}
|
||||
}
|
||||
|
||||
authorizationCode = oidcAuthorizationManager.createCode(clientId, redirectUri, scopes,
|
||||
principal.getUserId(), nonce, request.getSession().getId());
|
||||
}
|
||||
|
||||
uriBuilder.queryParam("code", authorizationCode.getCode());
|
||||
|
||||
if (StringUtils.hasText(state)) {
|
||||
uri += "&state=" + state;
|
||||
uriBuilder.queryParam("state", state);
|
||||
}
|
||||
|
||||
response.sendRedirect(uri);
|
||||
if (StringUtils.hasText(login_hint)) {
|
||||
uriBuilder.queryParam("login_hint", login_hint);
|
||||
}
|
||||
|
||||
response.sendRedirect(uriBuilder.build().toUriString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization get request.
|
||||
*
|
||||
* @param scope the scope
|
||||
* @param responseType the response type
|
||||
* @param clientId the client id
|
||||
* @param redirectUri the redirect uri
|
||||
* @param state the state
|
||||
* @param nonce the nonce
|
||||
* @param prompt the prompt
|
||||
* @param login_hint the login hint
|
||||
* @param principal the principal
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@GetMapping
|
||||
public void authorizationGetRequest(
|
||||
// for OIDC scope must contain "openid"
|
||||
@RequestParam(name = "scope") String scope,
|
||||
// response type
|
||||
@RequestParam(name = "response_type") String responseType,
|
||||
// client id
|
||||
@RequestParam(name = "client_id") String clientId,
|
||||
// redirect url
|
||||
@RequestParam(name = "redirect_uri") URI redirectUri,
|
||||
// optional state
|
||||
@RequestParam(name = "state", required = false) String state,
|
||||
// optional nonce
|
||||
@RequestParam(name = "nonce", required = false) String nonce,
|
||||
// optional prompt
|
||||
@RequestParam(name = "prompt", required = false) String prompt,
|
||||
// optional login_hint
|
||||
@RequestParam(name = "login_hint", required = false) String login_hint,
|
||||
// authentication details
|
||||
@AuthenticationPrincipal LocalUserDetails principal,
|
||||
// the request
|
||||
HttpServletRequest request,
|
||||
// the response
|
||||
HttpServletResponse response) throws IOException {
|
||||
authorizationRequest(scope, responseType, clientId, redirectUri, state, nonce, prompt, login_hint, null,
|
||||
principal, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization post request.
|
||||
*
|
||||
* @param authorizationRequest the authorization request
|
||||
* @param principal the principal
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
public void authorizationPostRequest(
|
||||
// authorization request
|
||||
@ModelAttribute("authorizationRequest") OidcAuthorizationRequest authorizationRequest,
|
||||
// authentication details
|
||||
@AuthenticationPrincipal LocalUserDetails principal,
|
||||
// the request
|
||||
HttpServletRequest request,
|
||||
// the response
|
||||
HttpServletResponse response) throws IOException {
|
||||
authorizationRequest(authorizationRequest.getScope(), authorizationRequest.getResponse_type(),
|
||||
authorizationRequest.getClient_id(), authorizationRequest.getRedirect_uri(),
|
||||
authorizationRequest.getState(), authorizationRequest.getNonce(), authorizationRequest.getPrompt(),
|
||||
authorizationRequest.getLogin_hint(), authorizationRequest.getCode(), principal, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,126 +284,21 @@ public class OidcAuthorizationController {
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@ExceptionHandler(InvalidAuthorizationRequestError.class)
|
||||
public void handle(InvalidAuthorizationRequestError exception, HttpServletResponse response) throws IOException {
|
||||
String uri = exception.getRedirectUri().toString();
|
||||
@ExceptionHandler(InvalidAuthorizationRequestException.class)
|
||||
public void handle(InvalidAuthorizationRequestException exception, HttpServletResponse response)
|
||||
throws IOException {
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUri(exception.getRedirectUri());
|
||||
|
||||
uri += "?error=" + exception.getErrorCode().getAuthorizationErrorCode();
|
||||
uriBuilder.queryParam("error", exception.getErrorCode().getAuthorizationErrorCode());
|
||||
|
||||
if (StringUtils.hasText(exception.getErrorDescription())) {
|
||||
uri += "&error_description=" + exception.getErrorDescription();
|
||||
uriBuilder.queryParam("error_description", exception.getErrorDescription());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(exception.getState())) {
|
||||
uri += "&state=" + exception.getState();
|
||||
uriBuilder.queryParam("state", exception.getState());
|
||||
}
|
||||
|
||||
response.sendRedirect(uri);
|
||||
response.sendRedirect(uriBuilder.build().toUriString());
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class InvalidAuthorizationRequestError.
|
||||
*/
|
||||
static class InvalidAuthorizationRequestError extends RuntimeException {
|
||||
/**
|
||||
* default serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private URI redirectUri;
|
||||
private OidcAuthorizationErrorCode errorCode;
|
||||
private String errorDescription;
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* Instantiates a new invalid authorization request error.
|
||||
*
|
||||
* @param redirectUri the redirect uri
|
||||
* @param errorCode the error code
|
||||
* @param errorDescription the error description
|
||||
* @param state the state
|
||||
*/
|
||||
InvalidAuthorizationRequestError(URI redirectUri, OidcAuthorizationErrorCode errorCode, String errorDescription,
|
||||
String state) {
|
||||
super(errorDescription);
|
||||
this.redirectUri = redirectUri;
|
||||
this.errorCode = errorCode;
|
||||
this.errorDescription = errorDescription;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redirect uri.
|
||||
*
|
||||
* @return the redirect uri
|
||||
*/
|
||||
public URI getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the redirect uri.
|
||||
*
|
||||
* @param redirectUri the new redirect uri
|
||||
*/
|
||||
public void setRedirectUri(URI redirectUri) {
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public OidcAuthorizationErrorCode getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error code.
|
||||
*
|
||||
* @param errorCode the new error code
|
||||
*/
|
||||
public void setErrorCode(OidcAuthorizationErrorCode errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public String getErrorDescription() {
|
||||
return errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error description.
|
||||
*
|
||||
* @param errorDescription the new error description
|
||||
*/
|
||||
public void setErrorDescription(String errorDescription) {
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state.
|
||||
*
|
||||
* @param state the new state
|
||||
*/
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,9 +9,8 @@ import java.net.URISyntaxException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -19,7 +18,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.bstly.we.controller.support.EntityResponseStatusException;
|
||||
import de.bstly.we.oidc.model.OidcConfiguration;
|
||||
import de.bstly.we.oidc.businesslogic.OidcClientManager;
|
||||
import de.bstly.we.oidc.controller.model.OidcConfiguration;
|
||||
|
||||
/**
|
||||
* The Class OidcDiscoveryController.
|
||||
@ -28,8 +28,8 @@ import de.bstly.we.oidc.model.OidcConfiguration;
|
||||
@RestController
|
||||
public class OidcDiscoveryController {
|
||||
|
||||
@Value("${oidc.provider.issuer:}")
|
||||
private String oidcIssuer;
|
||||
@Autowired
|
||||
private OidcClientManager oidcClientManager;
|
||||
|
||||
/**
|
||||
* Gets the configuration.
|
||||
@ -42,14 +42,7 @@ public class OidcDiscoveryController {
|
||||
public OidcConfiguration getConfiguration(HttpServletRequest request, HttpServletResponse response) {
|
||||
OidcConfiguration config = new OidcConfiguration();
|
||||
|
||||
String issuer = oidcIssuer;
|
||||
|
||||
if (!StringUtils.hasText(issuer)) {
|
||||
issuer = request.getScheme() + "://" + request.getServerName();
|
||||
if (request.getServerPort() != 443 && request.getServerPort() != 80) {
|
||||
issuer += ":" + request.getServerPort();
|
||||
}
|
||||
}
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
|
||||
config.setIssuer(issuer);
|
||||
config.setScopes_supported(Sets.newHashSet("openid"));
|
||||
|
@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import de.bstly.we.jwt.businesslogic.JwtKeyManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcTokenManager;
|
||||
|
||||
/**
|
||||
@ -20,7 +21,7 @@ import de.bstly.we.oidc.businesslogic.OidcTokenManager;
|
||||
public class OidcJwksController {
|
||||
|
||||
@Autowired
|
||||
private OidcTokenManager oidcTokenManager;
|
||||
private JwtKeyManager jwtKeyManager;
|
||||
|
||||
/**
|
||||
* Gets the jwks.
|
||||
@ -29,6 +30,6 @@ public class OidcJwksController {
|
||||
*/
|
||||
@GetMapping
|
||||
public Map<String, Object> getJwks() {
|
||||
return oidcTokenManager.getJwkSet().toJSONObject();
|
||||
return jwtKeyManager.getJwkSet(OidcTokenManager.OIDC_JWT_KEY_NAME, false).toJSONObject();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,234 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import de.bstly.we.businesslogic.PermissionManager;
|
||||
import de.bstly.we.businesslogic.Permissions;
|
||||
import de.bstly.we.businesslogic.SessionManager;
|
||||
import de.bstly.we.businesslogic.UserManager;
|
||||
import de.bstly.we.controller.BaseController;
|
||||
import de.bstly.we.controller.support.EntityResponseStatusException;
|
||||
import de.bstly.we.model.User;
|
||||
import de.bstly.we.oidc.businesslogic.OidcClientManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcSessionManager;
|
||||
import de.bstly.we.oidc.controller.model.OidcClientInfo;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcSession;
|
||||
|
||||
/**
|
||||
* The Class OidcSessionController.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/oidc/session")
|
||||
public class OidcSessionController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private OidcClientManager oidcClientManager;
|
||||
@Autowired
|
||||
private OidcSessionManager oidcSessionManager;
|
||||
@Autowired
|
||||
private SessionManager sessionManager;
|
||||
@Autowired
|
||||
private RememberMeServices rememberMeServices;
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
private OidcClientManager oidcRegisteredClientManager;
|
||||
@Autowired
|
||||
private PermissionManager permissionManager;
|
||||
|
||||
@Value("${loginUrl:/login}")
|
||||
private String loginUrl;
|
||||
|
||||
/**
|
||||
* Gets the sessions.
|
||||
*
|
||||
* @return the sessions
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@GetMapping
|
||||
public List<OidcClientInfo> getSessions() {
|
||||
Map<Long, OidcClientInfo> clients = Maps.newHashMap();
|
||||
for (OidcSession session : oidcSessionManager.getAllBySubject(getCurrentUserId())) {
|
||||
Long oidcClientId = session.getClientId();
|
||||
OidcClientInfo clientInfo = clients.get(oidcClientId);
|
||||
if (clientInfo == null) {
|
||||
OidcClient client = oidcRegisteredClientManager.get(oidcClientId);
|
||||
if (client == null || !client.isAlwaysPermitted()
|
||||
&& (!permissionManager.hasPermission(getCurrentUserId(), client.getClientName())
|
||||
|| !permissionManager.hasPermission(getCurrentUserId(), Permissions.ROLE_ADMIN))) {
|
||||
continue;
|
||||
}
|
||||
clientInfo = oidcRegisteredClientManager.getClientInfo(client, getCurrentUserId());
|
||||
}
|
||||
clientInfo.getSessions().add(session);
|
||||
clients.put(session.getClientId(), clientInfo);
|
||||
}
|
||||
|
||||
return Lists.newArrayList(clients.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sessions for target.
|
||||
*
|
||||
* @param target the target
|
||||
* @return the sessions for target
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@GetMapping("/{target}")
|
||||
public OidcClientInfo getSessionsForTarget(@PathVariable("target") Long target) {
|
||||
OidcClient client = oidcRegisteredClientManager.get(target);
|
||||
if (client == null || !client.isAlwaysPermitted()
|
||||
&& (!permissionManager.hasPermission(getCurrentUserId(), client.getClientName())
|
||||
|| !permissionManager.hasPermission(getCurrentUserId(), Permissions.ROLE_ADMIN))) {
|
||||
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
OidcClientInfo clientInfo = oidcRegisteredClientManager.getClientInfo(client, getCurrentUserId());
|
||||
clientInfo.getSessions().addAll(oidcSessionManager.getAllByTargetAndSubject(target, getCurrentUserId()));
|
||||
return clientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout session.
|
||||
*
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@RequestMapping(value = "/logout", method = { RequestMethod.GET, RequestMethod.POST })
|
||||
public void logoutSession(@RequestParam("redirect_url") Optional<String> redirectUrlParam,
|
||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
oidcSessionManager.backchannelLogout(request.getSession().getId(), issuer);
|
||||
internalLogout(redirectUrlParam, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout all.
|
||||
*
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@RequestMapping(value = "/logout/all", method = { RequestMethod.GET, RequestMethod.POST })
|
||||
public void logoutAll(@RequestParam("redirect_url") Optional<String> redirectUrlParam, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
oidcSessionManager.backchannelLogout(getCurrentUserId(), issuer);
|
||||
|
||||
User user = userManager.get(getCurrentUserId());
|
||||
sessionManager.deleteSessionsForUser(user);
|
||||
|
||||
internalLogout(redirectUrlParam, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout by sid.
|
||||
*
|
||||
* @param sid the sid
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@RequestMapping(value = "/logout/sid/{sid}", method = { RequestMethod.GET, RequestMethod.POST })
|
||||
public void logoutBySid(@PathVariable("sid") String sid,
|
||||
@RequestParam("redirect_url") Optional<String> redirectUrlParam, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
oidcSessionManager.backchannelLogout(sid, issuer);
|
||||
redirect(redirectUrlParam, request, response, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout all for target.
|
||||
*
|
||||
* @param target the target
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@RequestMapping(value = "/logout/all/{target}", method = { RequestMethod.GET, RequestMethod.POST })
|
||||
public void logoutAllForTarget(@PathVariable("target") Long target,
|
||||
@RequestParam("redirect_url") Optional<String> redirectUrlParam, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
oidcSessionManager.backchannelLogout(target, getCurrentUserId(), issuer);
|
||||
redirect(redirectUrlParam, request, response, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal logout.
|
||||
*
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected void internalLogout(Optional<String> redirectUrlParam, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
new SecurityContextLogoutHandler().logout(request, response,
|
||||
SecurityContextHolder.getContext().getAuthentication());
|
||||
rememberMeServices.loginFail(request, response);
|
||||
redirect(redirectUrlParam, request, response, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect.
|
||||
*
|
||||
* @param redirectUrlParam the redirect url param
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param fallback the fallback
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected void redirect(Optional<String> redirectUrlParam, HttpServletRequest request, HttpServletResponse response,
|
||||
boolean fallback) throws IOException {
|
||||
String redirectUrl = redirectUrlParam.orElse(null);
|
||||
|
||||
if (!StringUtils.hasText(redirectUrl) && fallback) {
|
||||
|
||||
redirectUrl = loginUrl;
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(redirectUrl)) {
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -11,15 +11,16 @@ import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
@ -32,16 +33,19 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
|
||||
import de.bstly.we.oidc.businesslogic.OidcAuthorizationCodeManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcAuthorizationManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcClientManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcSessionManager;
|
||||
import de.bstly.we.oidc.businesslogic.OidcTokenManager;
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.businesslogic.exception.InvalidTokenRequestException;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationCode;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcTokenErrorCode;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcTokenRequest;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcTokenResponse;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcTokenRevokeRequest;
|
||||
import de.bstly.we.oidc.model.OidcClient;
|
||||
import de.bstly.we.oidc.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.model.OidcToken;
|
||||
import de.bstly.we.oidc.model.OidcTokenErrorCode;
|
||||
import de.bstly.we.oidc.model.OidcTokenRequest;
|
||||
import de.bstly.we.oidc.model.OidcTokenResponse;
|
||||
|
||||
/**
|
||||
* The Class OidcTokenController.
|
||||
@ -57,12 +61,11 @@ public class OidcTokenController {
|
||||
@Autowired
|
||||
private OidcClientManager oidcClientManager;
|
||||
@Autowired
|
||||
private OidcAuthorizationCodeManager oidcAuthorizationCodeManager;
|
||||
private OidcAuthorizationManager oidcAuthorizationManager;
|
||||
@Autowired
|
||||
private OidcTokenManager oidcTokenManager;
|
||||
|
||||
@Value("${oidc.provider.issuer:}")
|
||||
private String oidcIssuer;
|
||||
@Autowired
|
||||
private OidcSessionManager oidcSessionManager;
|
||||
|
||||
/**
|
||||
* Gets the token.
|
||||
@ -74,6 +77,7 @@ public class OidcTokenController {
|
||||
* @return the token
|
||||
*/
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public OidcTokenResponse getToken(
|
||||
// Authorization header for BASIC client authentication method
|
||||
@RequestHeader(name = HttpHeaders.AUTHORIZATION, required = false) String authorizationHeader,
|
||||
@ -84,6 +88,8 @@ public class OidcTokenController {
|
||||
// the response
|
||||
HttpServletResponse response) {
|
||||
|
||||
String issuer = oidcClientManager.getIssuer(request);
|
||||
|
||||
response.setHeader(HttpHeaders.CACHE_CONTROL, "no-store");
|
||||
response.setHeader(HttpHeaders.PRAGMA, "no-cache");
|
||||
|
||||
@ -101,52 +107,61 @@ public class OidcTokenController {
|
||||
clientAuthenticationMethod = OidcClientAuthenticationMethod.basic;
|
||||
} else {
|
||||
logger.debug("invalid_basic_authentication: " + decoded);
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_CLIENT, "invalid_basic_authentication");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_CLIENT,
|
||||
"invalid_basic_authentication");
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(tokenRequest.getClient_id())) {
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_REQUEST, "missing_client_id");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(tokenRequest.getClient_secret())) {
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_REQUEST, "missing_client_secret");
|
||||
}
|
||||
|
||||
OidcClient client = oidcClientManager.getByClientIdAndSecret(tokenRequest.getClient_id(),
|
||||
tokenRequest.getClient_secret());
|
||||
|
||||
if (client == null) {
|
||||
logger.debug("client not found: " + tokenRequest.getClient_id());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_CLIENT, "invalid_client");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_CLIENT, "invalid_client");
|
||||
}
|
||||
|
||||
if (!client.getClientAuthenticationMethods().contains(clientAuthenticationMethod)) {
|
||||
logger.debug("invalid_authentication_method: " + clientAuthenticationMethod);
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_REQUEST, "invalid_authentication_method");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_REQUEST, "invalid_authentication_method");
|
||||
}
|
||||
|
||||
if (!client.getAuthorizationGrantTypes().contains(tokenRequest.getGrant_type())) {
|
||||
logger.debug("invalid_grant_type: " + tokenRequest.getGrant_type());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.UNAUTHORIZED_CLIENT, "invalid_grant_type");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.UNAUTHORIZED_CLIENT, "invalid_grant_type");
|
||||
}
|
||||
|
||||
if (tokenRequest.getRedirect_uri() != null
|
||||
&& !client.getRedirectUris().contains(tokenRequest.getRedirect_uri().toString())) {
|
||||
logger.debug("invalid redirect_uri: " + tokenRequest.getRedirect_uri().toString() + " allowed: "
|
||||
+ client.getRedirectUris());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_REQUEST, "invalid_redirect_uri");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_REQUEST, "invalid_redirect_uri");
|
||||
}
|
||||
|
||||
OidcToken token = null;
|
||||
switch (tokenRequest.getGrant_type()) {
|
||||
case authorization_code:
|
||||
OidcAuthorizationCode authorizationCode = oidcAuthorizationCodeManager.getByCode(tokenRequest.getCode());
|
||||
OidcAuthorizationCode authorizationCode = oidcAuthorizationManager.getCode(tokenRequest.getCode());
|
||||
if (authorizationCode == null) {
|
||||
logger.debug("invalid authorization code: " + tokenRequest.getCode());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_GRANT, "invalid_authorization_code");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_GRANT, "invalid_authorization_code");
|
||||
}
|
||||
if (Instant.now().isAfter(authorizationCode.getExpiry())) {
|
||||
logger.debug("authorization code expired: " + authorizationCode.getExpiry());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_GRANT, "invalid_authorization_code");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_GRANT, "invalid_authorization_code");
|
||||
}
|
||||
|
||||
if (!tokenRequest.getClient_id().equals(authorizationCode.getClientId())) {
|
||||
logger.debug("invalid client for authorization code, expected: " + authorizationCode.getClientId()
|
||||
+ " got: " + tokenRequest.getClient_id());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_CLIENT, "invalid_client");
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_CLIENT, "invalid_client");
|
||||
}
|
||||
|
||||
Set<String> scopes = StringUtils.hasText(tokenRequest.getScope())
|
||||
@ -155,46 +170,80 @@ public class OidcTokenController {
|
||||
|
||||
if (!scopes.contains("openid") || !client.getScopes().containsAll(scopes)) {
|
||||
logger.debug("missing openid scope: " + scopes + " - " + client.getClientName());
|
||||
throw new InvalidTokenRequestError(OidcTokenErrorCode.INVALID_SCOPE, "invalid scopes");
|
||||
}
|
||||
|
||||
String issuer = oidcIssuer;
|
||||
|
||||
if (!StringUtils.hasText(issuer)) {
|
||||
issuer = request.getScheme() + "://" + request.getServerName();
|
||||
if (request.getServerPort() != 443 && request.getServerPort() != 80) {
|
||||
issuer += ":" + request.getServerPort();
|
||||
}
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_SCOPE, "invalid scopes");
|
||||
}
|
||||
|
||||
try {
|
||||
String sid = oidcSessionManager.createSid();
|
||||
token = oidcTokenManager.createTokenWithIdToken(client, authorizationCode.getUserId(),
|
||||
authorizationCode.getNonce(), scopes, issuer);
|
||||
authorizationCode.getNonce(), scopes, issuer, sid);
|
||||
oidcSessionManager.createSession(client.getId(), authorizationCode.getUserId(), token.getIdToken(), sid,
|
||||
authorizationCode.getSpringSession());
|
||||
} catch (JOSEException e) {
|
||||
logger.error("error creating token", client, authorizationCode);
|
||||
e.printStackTrace();
|
||||
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
oidcAuthorizationCodeManager.removeByCode(tokenRequest.getCode());
|
||||
oidcAuthorizationManager.removeCode(tokenRequest.getCode());
|
||||
break;
|
||||
case client_credentials:
|
||||
token = oidcTokenManager.createToken(client, client.getId());
|
||||
token = oidcTokenManager.createToken(client, client.getId(), false);
|
||||
break;
|
||||
case refresh_token:
|
||||
if (!StringUtils.hasText(tokenRequest.getRefresh_token())) {
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_GRANT, "invalid_refresh_token");
|
||||
}
|
||||
|
||||
OidcToken refreshToken = oidcTokenManager.getLastByRefreshToken(tokenRequest.getRefresh_token());
|
||||
|
||||
if (refreshToken == null || !(client.getId().equals(refreshToken.getClient()))) {
|
||||
throw new InvalidTokenRequestException(OidcTokenErrorCode.INVALID_GRANT, "invalid_refresh_token");
|
||||
}
|
||||
|
||||
token = oidcTokenManager.createToken(client, client.getId(), tokenRequest.getRefresh_token());
|
||||
token.setRefreshToken(null);
|
||||
break;
|
||||
}
|
||||
|
||||
if (token == null) {
|
||||
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
OidcTokenResponse tokenResponse = new OidcTokenResponse();
|
||||
|
||||
tokenResponse.setAccess_token(token.getAccessToken());
|
||||
if (StringUtils.hasText(token.getRefreshToken())) {
|
||||
tokenResponse.setRefresh_token(token.getRefreshToken());
|
||||
}
|
||||
if (StringUtils.hasText(token.getIdToken())) {
|
||||
tokenResponse.setId_token(token.getIdToken());
|
||||
}
|
||||
tokenResponse.setToken_type(OidcTokenManager.BEARER_TOKEN_TYPE);
|
||||
tokenResponse.setExpires_in(client.getTokenLifetime());
|
||||
|
||||
oidcAuthorizationCodeManager.removeByCode(tokenRequest.getCode());
|
||||
|
||||
tokenResponse.setExpires_in(token.getExpiresIn());
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke.
|
||||
*
|
||||
* @param oidcTokenRevokeRequest the oidc token revoke request
|
||||
*/
|
||||
@PreAuthorize("authentication.authenticated")
|
||||
@PostMapping("revoke")
|
||||
@Transactional
|
||||
public void revoke(@ModelAttribute("oidcTokenRevokeRequest") OidcTokenRevokeRequest oidcTokenRevokeRequest) {
|
||||
if (!StringUtils.hasText(oidcTokenRevokeRequest.getToken())) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ("refresh_token".equals(oidcTokenRevokeRequest.getToken_type_hint())) {
|
||||
oidcTokenManager.deleteAllByRefreshToken(oidcTokenRevokeRequest.getToken());
|
||||
} else if ("access_token".equals(oidcTokenRevokeRequest.getToken_type_hint())
|
||||
|| oidcTokenRevokeRequest.getToken_type_hint() == null) {
|
||||
oidcTokenManager.deleteByAccessToken(oidcTokenRevokeRequest.getToken());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle.
|
||||
*
|
||||
@ -203,74 +252,11 @@ public class OidcTokenController {
|
||||
* @return the response entity
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
@ExceptionHandler(InvalidTokenRequestError.class)
|
||||
public ResponseEntity<String> handle(InvalidTokenRequestError exception, HttpServletResponse response)
|
||||
@ExceptionHandler(InvalidTokenRequestException.class)
|
||||
public ResponseEntity<String> handle(InvalidTokenRequestException exception, HttpServletResponse response)
|
||||
throws IOException {
|
||||
// response.sendError(400, "redirect uri mismatch");
|
||||
return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON)
|
||||
.body(" {\"error\": \"" + exception.getMessage() + "\"}");
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class InvalidTokenRequestError.
|
||||
*/
|
||||
static class InvalidTokenRequestError extends RuntimeException {
|
||||
|
||||
/**
|
||||
* default serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private OidcTokenErrorCode errorCode;
|
||||
private String errorDescription;
|
||||
|
||||
/**
|
||||
* Instantiates a new invalid token request error.
|
||||
*
|
||||
* @param errorCode the error code
|
||||
* @param errorDescription the error description
|
||||
*/
|
||||
InvalidTokenRequestError(OidcTokenErrorCode errorCode, String errorDescription) {
|
||||
super(errorDescription);
|
||||
this.errorCode = errorCode;
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public OidcTokenErrorCode getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error code.
|
||||
*
|
||||
* @param errorCode the new error code
|
||||
*/
|
||||
public void setErrorCode(OidcTokenErrorCode errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public String getErrorDescription() {
|
||||
return errorDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error description.
|
||||
*
|
||||
* @param errorDescription the new error description
|
||||
*/
|
||||
public void setErrorDescription(String errorDescription) {
|
||||
this.errorDescription = errorDescription;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,266 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.controller.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcSession;
|
||||
|
||||
/**
|
||||
* The Class OidcClientInfo.
|
||||
*/
|
||||
public class OidcClientInfo {
|
||||
|
||||
private String clientId;
|
||||
private String name;
|
||||
private String description;
|
||||
private String loginUrl;
|
||||
private String frontchannelLogoutUri;
|
||||
private boolean frontchannelLogoutSessionRequired;
|
||||
private boolean backchannelLogout;
|
||||
private boolean authorize;
|
||||
private Set<String> scopes;
|
||||
private Map<String, Set<String>> claimMapping;
|
||||
private Set<String> authorizedScopes;
|
||||
private Map<String, Object> claims;
|
||||
private List<OidcSession> sessions;
|
||||
|
||||
/**
|
||||
* Gets the client id.
|
||||
*
|
||||
* @return the client id
|
||||
*/
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client id.
|
||||
*
|
||||
* @param clientId the new client id
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name.
|
||||
*
|
||||
* @param name the new name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description.
|
||||
*
|
||||
* @param description the new description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login url.
|
||||
*
|
||||
* @return the login url
|
||||
*/
|
||||
public String getLoginUrl() {
|
||||
return loginUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the login url.
|
||||
*
|
||||
* @param loginUrl the new login url
|
||||
*/
|
||||
public void setLoginUrl(String loginUrl) {
|
||||
this.loginUrl = loginUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frontchannel logout uri.
|
||||
*
|
||||
* @return the frontchannel logout uri
|
||||
*/
|
||||
public String getFrontchannelLogoutUri() {
|
||||
return frontchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frontchannel logout uri.
|
||||
*
|
||||
* @param frontchannelLogoutUri the new frontchannel logout uri
|
||||
*/
|
||||
public void setFrontchannelLogoutUri(String frontchannelLogoutUri) {
|
||||
this.frontchannelLogoutUri = frontchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is frontchannel logout session required.
|
||||
*
|
||||
* @return true, if is frontchannel logout session required
|
||||
*/
|
||||
public boolean isFrontchannelLogoutSessionRequired() {
|
||||
return frontchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frontchannel logout session required.
|
||||
*
|
||||
* @param frontchannelLogoutSessionRequired the new frontchannel logout session
|
||||
* required
|
||||
*/
|
||||
public void setFrontchannelLogoutSessionRequired(boolean frontchannelLogoutSessionRequired) {
|
||||
this.frontchannelLogoutSessionRequired = frontchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is backchannel logout.
|
||||
*
|
||||
* @return true, if is backchannel logout
|
||||
*/
|
||||
public boolean isBackchannelLogout() {
|
||||
return backchannelLogout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backchannel logout.
|
||||
*
|
||||
* @param backchannelLogout the new backchannel logout
|
||||
*/
|
||||
public void setBackchannelLogout(boolean backchannelLogout) {
|
||||
this.backchannelLogout = backchannelLogout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is authorize.
|
||||
*
|
||||
* @return true, if is authorize
|
||||
*/
|
||||
public boolean isAuthorize() {
|
||||
return authorize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authorize.
|
||||
*
|
||||
* @param authorize the new authorize
|
||||
*/
|
||||
public void setAuthorize(boolean authorize) {
|
||||
this.authorize = authorize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scopes.
|
||||
*
|
||||
* @return the scopes
|
||||
*/
|
||||
public Set<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scopes.
|
||||
*
|
||||
* @param scopes the new scopes
|
||||
*/
|
||||
public void setScopes(Set<String> scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the claim mapping.
|
||||
*
|
||||
* @return the claim mapping
|
||||
*/
|
||||
public Map<String, Set<String>> getClaimMapping() {
|
||||
return claimMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the claim mapping.
|
||||
*
|
||||
* @param claimMapping the claim mapping
|
||||
*/
|
||||
public void setClaimMapping(Map<String, Set<String>> claimMapping) {
|
||||
this.claimMapping = claimMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authorized scopes.
|
||||
*
|
||||
* @return the authorized scopes
|
||||
*/
|
||||
public Set<String> getAuthorizedScopes() {
|
||||
return authorizedScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authorized scopes.
|
||||
*
|
||||
* @param authorizedScopes the new authorized scopes
|
||||
*/
|
||||
public void setAuthorizedScopes(Set<String> authorizedScopes) {
|
||||
this.authorizedScopes = authorizedScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the claims.
|
||||
*
|
||||
* @return the claims
|
||||
*/
|
||||
public Map<String, Object> getClaims() {
|
||||
return claims;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the claims.
|
||||
*
|
||||
* @param claims the claims
|
||||
*/
|
||||
public void setClaims(Map<String, Object> claims) {
|
||||
this.claims = claims;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sessions.
|
||||
*
|
||||
* @return the sessions
|
||||
*/
|
||||
public List<OidcSession> getSessions() {
|
||||
return sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sessions.
|
||||
*
|
||||
* @param sessions the new sessions
|
||||
*/
|
||||
public void setSessions(List<OidcSession> sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
}
|
@ -5,8 +5,8 @@ package de.bstly.we.oidc.controller.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.model.OidcClientAuthenticationMethod;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcClientAuthenticationMethod;
|
||||
|
||||
/**
|
||||
* The Class OidcClientModel.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
package de.bstly.we.oidc.controller.model;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
|
||||
/**
|
||||
* The Class OidcAuthorization.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "oidc_authorizations")
|
||||
public class OidcAuthorization {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
@Column(name = "client_id")
|
||||
private Long client;
|
||||
@Column(name = "subject")
|
||||
private Long subject;
|
||||
@ElementCollection
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@CollectionTable(name = "oidc_authorizations_scopes")
|
||||
private Set<String> scopes;
|
||||
|
||||
/**
|
||||
* Gets the client.
|
||||
*
|
||||
* @return the client
|
||||
*/
|
||||
public Long getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client.
|
||||
*
|
||||
* @param client the new client
|
||||
*/
|
||||
public void setClient(Long client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subject.
|
||||
*
|
||||
* @return the subject
|
||||
*/
|
||||
public Long getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subject.
|
||||
*
|
||||
* @param subject the new subject
|
||||
*/
|
||||
public void setSubject(Long subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scopes.
|
||||
*
|
||||
* @return the scopes
|
||||
*/
|
||||
public Set<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scopes.
|
||||
*
|
||||
* @param scopes the new scopes
|
||||
*/
|
||||
public void setScopes(Set<String> scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
|
||||
/**
|
||||
* The Enum OidcAuthorizationResponseType.
|
||||
*/
|
||||
public enum OidcAuthorizationResponseType {
|
||||
code
|
||||
}
|
@ -19,6 +19,9 @@ import javax.persistence.Table;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcAuthorizationGrantType;
|
||||
import de.bstly.we.oidc.businesslogic.model.OidcClientAuthenticationMethod;
|
||||
|
||||
/**
|
||||
* The Class OidcClient.
|
||||
*/
|
||||
@ -58,6 +61,16 @@ public class OidcClient {
|
||||
private Long tokenLifetime;
|
||||
@Column(name = "login_url", length = 1024)
|
||||
private String loginUrl;
|
||||
@Column(name = "frontchannel_logout_uri")
|
||||
private String frontchannelLogoutUri;
|
||||
@Column(name = "frontchannel_logout_session_required", columnDefinition = "boolean default false")
|
||||
private boolean frontchannelLogoutSessionRequired;
|
||||
@Column(name = "backchannel_logout_uri")
|
||||
private String backchannelLogoutUri;
|
||||
@Column(name = "backchannel_logout_session_required", columnDefinition = "boolean default false")
|
||||
private boolean backchannelLogoutSessionRequired;
|
||||
@Column(name = "authorize", columnDefinition = "boolean default false")
|
||||
private boolean authorize;
|
||||
@Column(name = "always_permitted", columnDefinition = "boolean default false")
|
||||
private boolean alwaysPermitted;
|
||||
@Column(name = "category")
|
||||
@ -243,6 +256,98 @@ public class OidcClient {
|
||||
this.loginUrl = loginUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frontchannel logout uri.
|
||||
*
|
||||
* @return the frontchannel logout uri
|
||||
*/
|
||||
public String getFrontchannelLogoutUri() {
|
||||
return frontchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frontchannel logout uri.
|
||||
*
|
||||
* @param frontchannelLogoutUri the new frontchannel logout uri
|
||||
*/
|
||||
public void setFrontchannelLogoutUri(String frontchannelLogoutUri) {
|
||||
this.frontchannelLogoutUri = frontchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is frontchannel logout session required.
|
||||
*
|
||||
* @return true, if is frontchannel logout session required
|
||||
*/
|
||||
public boolean isFrontchannelLogoutSessionRequired() {
|
||||
return frontchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frontchannel logout session required.
|
||||
*
|
||||
* @param frontchannelLogoutSessionRequired the new frontchannel logout session
|
||||
* required
|
||||
*/
|
||||
public void setFrontchannelLogoutSessionRequired(boolean frontchannelLogoutSessionRequired) {
|
||||
this.frontchannelLogoutSessionRequired = frontchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the backchannel logout uri.
|
||||
*
|
||||
* @return the backchannel logout uri
|
||||
*/
|
||||
public String getBackchannelLogoutUri() {
|
||||
return backchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backchannel logout uri.
|
||||
*
|
||||
* @param backchannelLogoutUri the new backchannel logout uri
|
||||
*/
|
||||
public void setBackchannelLogoutUri(String backchannelLogoutUri) {
|
||||
this.backchannelLogoutUri = backchannelLogoutUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is backchannel logout session required.
|
||||
*
|
||||
* @return true, if is backchannel logout session required
|
||||
*/
|
||||
public boolean isBackchannelLogoutSessionRequired() {
|
||||
return backchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backchannel logout session required.
|
||||
*
|
||||
* @param backchannelLogoutSessionRequired the new backchannel logout session
|
||||
* required
|
||||
*/
|
||||
public void setBackchannelLogoutSessionRequired(boolean backchannelLogoutSessionRequired) {
|
||||
this.backchannelLogoutSessionRequired = backchannelLogoutSessionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is authorize.
|
||||
*
|
||||
* @return true, if is authorize
|
||||
*/
|
||||
public boolean isAuthorize() {
|
||||
return authorize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authorize.
|
||||
*
|
||||
* @param authorize the new authorize
|
||||
*/
|
||||
public void setAuthorize(boolean authorize) {
|
||||
this.authorize = authorize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is always permitted.
|
||||
*
|
||||
|
143
oidc/src/main/java/de/bstly/we/oidc/model/OidcSession.java
Normal file
143
oidc/src/main/java/de/bstly/we/oidc/model/OidcSession.java
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* The Class OidcSession.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "oidc_sessions")
|
||||
public class OidcSession {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
@Column(name = "client_id")
|
||||
private Long client;
|
||||
@Column(name = "subject")
|
||||
private Long subject;
|
||||
@Column(name = "sid")
|
||||
private String sid;
|
||||
@Column(name = "id_token", length = 4000)
|
||||
private String idToken;
|
||||
@Column(name = "spring_session_id")
|
||||
private String springSession;
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id.
|
||||
*
|
||||
* @param id the new id
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client id.
|
||||
*
|
||||
* @return the client id
|
||||
*/
|
||||
public Long getClientId() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client id.
|
||||
*
|
||||
* @param clientId the new client id
|
||||
*/
|
||||
public void setClientId(Long clientId) {
|
||||
this.client = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subject.
|
||||
*
|
||||
* @return the subject
|
||||
*/
|
||||
public Long getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subject.
|
||||
*
|
||||
* @param subject the new subject
|
||||
*/
|
||||
public void setSubject(Long subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sid.
|
||||
*
|
||||
* @return the sid
|
||||
*/
|
||||
public String getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sid.
|
||||
*
|
||||
* @param sid the new sid
|
||||
*/
|
||||
public void setSid(String sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id token.
|
||||
*
|
||||
* @return the id token
|
||||
*/
|
||||
public String getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id token.
|
||||
*
|
||||
* @param idToken the new id token
|
||||
*/
|
||||
public void setIdToken(String idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the spring session.
|
||||
*
|
||||
* @return the spring session
|
||||
*/
|
||||
public String getSpringSession() {
|
||||
return springSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the spring session.
|
||||
*
|
||||
* @param springSession the new spring session
|
||||
*/
|
||||
public void setSpringSession(String springSession) {
|
||||
this.springSession = springSession;
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
*/
|
||||
package de.bstly.we.oidc.model;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@ -29,6 +30,8 @@ public class OidcToken {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
@Column(name = "created")
|
||||
private Instant created;
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
@Column(name = "client_id")
|
||||
@ -64,6 +67,24 @@ public class OidcToken {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the created.
|
||||
*
|
||||
* @return the created
|
||||
*/
|
||||
public Instant getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the created.
|
||||
*
|
||||
* @param created the new created
|
||||
*/
|
||||
public void setCreated(Instant created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user id.
|
||||
*
|
||||
|
@ -0,0 +1,18 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcAuthorization;
|
||||
|
||||
/**
|
||||
* The Interface OidcAuthorizationRepository.
|
||||
*/
|
||||
@Repository
|
||||
public interface OidcAuthorizationRepository
|
||||
extends JpaRepository<OidcAuthorization, Long>, QuerydslPredicateExecutor<OidcAuthorization> {
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package de.bstly.we.oidc.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.bstly.we.oidc.model.OidcSession;
|
||||
|
||||
/**
|
||||
* The Interface OidcSessionRepository.
|
||||
*/
|
||||
@Repository
|
||||
public interface OidcSessionRepository
|
||||
extends JpaRepository<OidcSession, Long>, QuerydslPredicateExecutor<OidcSession> {
|
||||
}
|
@ -14,33 +14,20 @@ import de.bstly.we.partey.model.GameRoomPolicyTypes;
|
||||
*/
|
||||
public class MapDetailsData {
|
||||
|
||||
private String roomSlug = "";
|
||||
private String mapUrl = "";
|
||||
private GameRoomPolicyTypes policy_type = GameRoomPolicyTypes.ANONYMOUS_POLICY;
|
||||
private List<String> tags = Lists.newArrayList();
|
||||
private List<CharacterTexture> textures = Lists.newArrayList();
|
||||
private String contactPage = "";
|
||||
private boolean authenticationMandatory;
|
||||
private String group = "";
|
||||
private String roomSlug;
|
||||
private String contactPage;
|
||||
private String group;
|
||||
private String iframeAuthentication;
|
||||
|
||||
/**
|
||||
* Gets the room slug.
|
||||
*
|
||||
* @return the room slug
|
||||
*/
|
||||
public String getRoomSlug() {
|
||||
return roomSlug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the room slug.
|
||||
*
|
||||
* @param roomSlug the new room slug
|
||||
*/
|
||||
public void setRoomSlug(String roomSlug) {
|
||||
this.roomSlug = roomSlug;
|
||||
}
|
||||
private String miniLogo;
|
||||
private String loadingLogo;
|
||||
private String loginSceneLogo;
|
||||
private boolean showPoweredBy = false;
|
||||
private String loadingCowebsiteLogo;
|
||||
private boolean canReport = true;
|
||||
|
||||
/**
|
||||
* Gets the map url.
|
||||
@ -97,21 +84,39 @@ public class MapDetailsData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the textures.
|
||||
* Checks if is authentication mandatory.
|
||||
*
|
||||
* @return the textures
|
||||
* @return true, if is authentication mandatory
|
||||
*/
|
||||
public List<CharacterTexture> getTextures() {
|
||||
return textures;
|
||||
public boolean isAuthenticationMandatory() {
|
||||
return authenticationMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the textures.
|
||||
* Sets the authentication mandatory.
|
||||
*
|
||||
* @param textures the new textures
|
||||
* @param authenticationMandatory the new authentication mandatory
|
||||
*/
|
||||
public void setTextures(List<CharacterTexture> textures) {
|
||||
this.textures = textures;
|
||||
public void setAuthenticationMandatory(boolean authenticationMandatory) {
|
||||
this.authenticationMandatory = authenticationMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the room slug.
|
||||
*
|
||||
* @return the room slug
|
||||
*/
|
||||
public String getRoomSlug() {
|
||||
return roomSlug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the room slug.
|
||||
*
|
||||
* @param roomSlug the new room slug
|
||||
*/
|
||||
public void setRoomSlug(String roomSlug) {
|
||||
this.roomSlug = roomSlug;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,24 +137,6 @@ public class MapDetailsData {
|
||||
this.contactPage = contactPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is authentication mandatory.
|
||||
*
|
||||
* @return true, if is authentication mandatory
|
||||
*/
|
||||
public boolean isAuthenticationMandatory() {
|
||||
return authenticationMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authentication mandatory.
|
||||
*
|
||||
* @param authenticationMandatory the new authentication mandatory
|
||||
*/
|
||||
public void setAuthenticationMandatory(boolean authenticationMandatory) {
|
||||
this.authenticationMandatory = authenticationMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group.
|
||||
*
|
||||
@ -186,4 +173,112 @@ public class MapDetailsData {
|
||||
this.iframeAuthentication = iframeAuthentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mini logo.
|
||||
*
|
||||
* @return the mini logo
|
||||
*/
|
||||
public String getMiniLogo() {
|
||||
return miniLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mini logo.
|
||||
*
|
||||
* @param miniLogo the new mini logo
|
||||
*/
|
||||
public void setMiniLogo(String miniLogo) {
|
||||
this.miniLogo = miniLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the loading logo.
|
||||
*
|
||||
* @return the loading logo
|
||||
*/
|
||||
public String getLoadingLogo() {
|
||||
return loadingLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loading logo.
|
||||
*
|
||||
* @param loadingLogo the new loading logo
|
||||
*/
|
||||
public void setLoadingLogo(String loadingLogo) {
|
||||
this.loadingLogo = loadingLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login scene logo.
|
||||
*
|
||||
* @return the login scene logo
|
||||
*/
|
||||
public String getLoginSceneLogo() {
|
||||
return loginSceneLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the login scene logo.
|
||||
*
|
||||
* @param loginSceneLogo the new login scene logo
|
||||
*/
|
||||
public void setLoginSceneLogo(String loginSceneLogo) {
|
||||
this.loginSceneLogo = loginSceneLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is show powered by.
|
||||
*
|
||||
* @return true, if is show powered by
|
||||
*/
|
||||
public boolean isShowPoweredBy() {
|
||||
return showPoweredBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the show powered by.
|
||||
*
|
||||
* @param showPoweredBy the new show powered by
|
||||
*/
|
||||
public void setShowPoweredBy(boolean showPoweredBy) {
|
||||
this.showPoweredBy = showPoweredBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the loading cowebsite logo.
|
||||
*
|
||||
* @return the loading cowebsite logo
|
||||
*/
|
||||
public String getLoadingCowebsiteLogo() {
|
||||
return loadingCowebsiteLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loading cowebsite logo.
|
||||
*
|
||||
* @param loadingCowebsiteLogo the new loading cowebsite logo
|
||||
*/
|
||||
public void setLoadingCowebsiteLogo(String loadingCowebsiteLogo) {
|
||||
this.loadingCowebsiteLogo = loadingCowebsiteLogo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is can report.
|
||||
*
|
||||
* @return true, if is can report
|
||||
*/
|
||||
public boolean isCanReport() {
|
||||
return canReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the can report.
|
||||
*
|
||||
* @param canReport the new can report
|
||||
*/
|
||||
public void setCanReport(boolean canReport) {
|
||||
this.canReport = canReport;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -189,6 +189,27 @@ public class ParteyUserTag implements UserData {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ParteyUserTagId) {
|
||||
ParteyUserTagId parteyUserTagId = (ParteyUserTagId) obj;
|
||||
return this.target.equals(parteyUserTagId.getTarget()) && this.tag.equals(parteyUserTagId.getTag());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.target.hashCode() * this.tag.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user