oidc alias login

This commit is contained in:
_Bastler 2022-12-27 20:42:23 +01:00
parent f618d1c1a7
commit e20266f147
9 changed files with 109 additions and 31 deletions

View File

@ -20,8 +20,11 @@ import com.google.common.collect.Lists;
import de.bstly.we.model.Permission;
import de.bstly.we.model.QPermission;
import de.bstly.we.model.QUser;
import de.bstly.we.model.QUserAlias;
import de.bstly.we.model.User;
import de.bstly.we.model.UserAlias;
import de.bstly.we.repository.PermissionRepository;
import de.bstly.we.repository.UserAliasRepository;
import de.bstly.we.repository.UserRepository;
import de.bstly.we.security.model.LocalUserDetails;
@ -35,9 +38,12 @@ public class LocalUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
@Autowired
private PermissionRepository permissionRepository;
@Autowired
private UserAliasRepository userAliasRepository;
private QUser qUser = QUser.user;
private QPermission qPermission = QPermission.permission;
private QUserAlias qUserAlias = QUserAlias.userAlias;
/*
* @see org.springframework.security.core.userdetails.UserDetailsService#
@ -46,6 +52,16 @@ public class LocalUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findOne(qUser.username.equalsIgnoreCase(username)).orElse(null);
String alias = null;
if (user == null) {
UserAlias userAlias = userAliasRepository.findOne(qUserAlias.alias.eq(username)).orElse(null);
if (userAlias != null) {
user = userRepository.findOne(qUser.id.eq(userAlias.getTarget())).orElse(null);
alias = username;
}
}
if (user != null) {
String password = userRepository.findById(user.getId()).get().getPasswordHash();
@ -64,26 +80,8 @@ public class LocalUserDetailsService implements UserDetailsService {
Set<GrantedAuthority> authorities = getAuthoritiesForUser(user.getId());
// ignore and use status
// boolean onlyAddons = true;
// for (Permission permission : permissionManager
// .getNotExpiresByTargetIgnoreStart(user.getId())) {
// if (!permission.isAddon()) {
// onlyAddons = false;
// break;
// }
// }
//
// if (authorities.isEmpty()) {
// throw new AccountExpiredException("User is expired: " + username);
// }
//
// if (onlyAddons) {
// throw new AccountExpiredException("User is expired: " + username);
// }
// Create user details
LocalUserDetails userDetails = new LocalUserDetails(user.getId(), user.getUsername(), password,
LocalUserDetails userDetails = new LocalUserDetails(user.getId(), user.getUsername(), alias, password,
authorities);
return userDetails;

View File

@ -55,7 +55,7 @@ public class LocalAnonymousAuthenticationFilter extends AnonymousAuthenticationF
@Override
protected Authentication createAuthentication(HttpServletRequest request) {
Authentication authentication = new LocalAnonymousAuthenticationToken(
new LocalUserDetails(-1L, LocalAnonymousAuthenticationToken.ANONYMOUS_USERNAME, "",
new LocalUserDetails(-1L, LocalAnonymousAuthenticationToken.ANONYMOUS_USERNAME, "", "",
LocalAnonymousAuthenticationToken.AUTHORITIES));
authentication.setAuthenticated(false);
return authentication;

View File

@ -28,11 +28,12 @@ public class LocalUserDetails extends User {
* @param password the password
* @param authorities the authorities
*/
public LocalUserDetails(Long userId, String username, String password,
public LocalUserDetails(Long userId, String username, String alias, String password,
Collection<? extends GrantedAuthority> authorities) {
// Super
super(username, password, authorities);
this.userId = userId;
this.alias = alias;
}
/**

View File

@ -4,12 +4,14 @@
package de.bstly.we.oidc.businesslogic;
import java.net.URI;
import java.util.List;
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.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -34,6 +36,10 @@ public class OidcAuthorizationManager {
*/
private final Map<String, OidcAuthorizationCode> authorizationCodes = Maps.newHashMap();
public List<OidcAuthorization> getAuthorizations(Long subject) {
return Lists.newArrayList(oidcAuthorizationRepository.findAll(qOidcAuthorization.subject.eq(subject)));
}
/**
* Gets the authorization.
*

View File

@ -80,6 +80,8 @@ public class OidcTokenManager implements SmartInitializingSingleton {
private QuotaManager quotaManager;
@Autowired
private JwtKeyManager jwtKeyManager;
@Autowired
private OidcClientManager oidcClientManager;
private QOidcToken qOidcToken = QOidcToken.oidcToken;
/*
@ -230,6 +232,9 @@ public class OidcTokenManager implements SmartInitializingSingleton {
if (StringUtils.hasText(alias) && client.isAliasAllowed()) {
username = alias;
if (client.isAliasSubject()) {
claimsSetBuilder.subject(alias);
}
}
claimsSetBuilder.claim("name", username);
@ -265,8 +270,11 @@ public class OidcTokenManager implements SmartInitializingSingleton {
Map<String, String> permissions = Maps.newHashMap();
for (Permission permission : permissionManager.getNotExpiresByTarget(user.getId())) {
if (oidcClientManager.getByClientName(permission.getName()) == null
|| permission.getName().equals(client.getClientName())) {
permissions.put(permission.getName(), permission.getExpires().toString());
}
}
if (!permissions.isEmpty()) {
claimsSetBuilder.claim("permissions", permissions);
@ -274,8 +282,10 @@ public class OidcTokenManager implements SmartInitializingSingleton {
Map<String, String> quotas = Maps.newHashMap();
for (Quota quota : quotaManager.getNotExpiresByTarget(user.getId())) {
if (quota.getName().equals(client.getClientName()) && (!username.equals(alias) || client.isAliasQuota())) {
quotas.put(quota.getName(), String.valueOf(quota.getValue()) + quota.getUnit());
}
}
if (!quotas.isEmpty()) {
claimsSetBuilder.claim("quotas", quotas);

View File

@ -5,6 +5,7 @@ package de.bstly.we.oidc.controller;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@ -14,23 +15,29 @@ 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.HttpStatus;
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.DeleteMapping;
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.PathVariable;
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.beust.jcommander.internal.Lists;
import com.google.common.collect.Sets;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.Permissions;
import de.bstly.we.businesslogic.UserAliasManager;
import de.bstly.we.controller.BaseController;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.oidc.businesslogic.OidcAuthorizationManager;
import de.bstly.we.oidc.businesslogic.OidcClientManager;
import de.bstly.we.oidc.businesslogic.exception.InvalidAuthorizationRequestException;
@ -39,6 +46,8 @@ 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.controller.model.OidcClientInfo;
import de.bstly.we.oidc.model.OidcAuthorization;
import de.bstly.we.oidc.model.OidcClient;
import de.bstly.we.security.model.LocalUserDetails;
@ -47,7 +56,7 @@ import de.bstly.we.security.model.LocalUserDetails;
*/
@RequestMapping("/oidc/authorize")
@RestController
public class OidcAuthorizationController {
public class OidcAuthorizationController extends BaseController {
private Logger logger = LoggerFactory.getLogger(OidcAuthorizationController.class);
@ -318,4 +327,28 @@ public class OidcAuthorizationController {
response.sendRedirect(uriBuilder.build().toUriString());
}
@PreAuthorize("isAuthenticated()")
@GetMapping("history")
public List<OidcClientInfo> getAuthorizations() {
List<OidcClientInfo> result = Lists.newArrayList();
for (OidcAuthorization authorization : oidcAuthorizationManager.getAuthorizations(getCurrentUserId())) {
OidcClient client = oidcClientManager.get(authorization.getClient());
result.add(oidcClientManager.getClientInfo(client, getCurrentUserId()));
}
return result;
}
@PreAuthorize("isAuthenticated()")
@DeleteMapping("{name}")
public void revokeAuthorization(@PathVariable("name") String clientName) {
OidcClient client = oidcClientManager.getByClientName(clientName);
if (client == null
|| !oidcAuthorizationManager.isAuthorized(client.getId(), getCurrentUserId(), client.getScopes())) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
oidcAuthorizationManager.removeAuthorization(client.getId(), getCurrentUserId());
}
}

View File

@ -35,7 +35,7 @@ import de.bstly.we.oidc.repository.OidcClientRepository;
*/
@RestController
@RequestMapping("/oidc/clients")
public class OIDCClientController extends BaseController {
public class OidcClientController extends BaseController {
@Autowired
private OidcClientManager registeredClientService;

View File

@ -60,8 +60,6 @@ public class OidcSessionController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private OidcClientManager oidcRegisteredClientManager;
@Autowired
private PermissionManager permissionManager;
@Value("${loginUrl:/login}")
@ -80,13 +78,13 @@ public class OidcSessionController extends BaseController {
Long oidcClientId = session.getClientId();
OidcClientInfo clientInfo = clients.get(oidcClientId);
if (clientInfo == null) {
OidcClient client = oidcRegisteredClientManager.get(oidcClientId);
OidcClient client = oidcClientManager.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 = oidcClientManager.getClientInfo(client, getCurrentUserId());
}
clientInfo.getSessions().add(session);
clients.put(session.getClientId(), clientInfo);
@ -104,14 +102,14 @@ public class OidcSessionController extends BaseController {
@PreAuthorize("authentication.authenticated")
@GetMapping("/{target}")
public OidcClientInfo getSessionsForTarget(@PathVariable("target") Long target) {
OidcClient client = oidcRegisteredClientManager.get(target);
OidcClient client = oidcClientManager.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());
OidcClientInfo clientInfo = oidcClientManager.getClientInfo(client, getCurrentUserId());
clientInfo.getSessions().addAll(oidcSessionManager.getAllByTargetAndSubject(target, getCurrentUserId()));
return clientInfo;
}

View File

@ -73,6 +73,10 @@ public class OidcClient {
private boolean authorize;
@Column(name = "alias_allowed", columnDefinition = "boolean default false")
private boolean aliasAllowed;
@Column(name = "alias_quota", columnDefinition = "boolean default false")
private boolean aliasQuota;
@Column(name = "alias_sub", columnDefinition = "boolean default true")
private boolean aliasSubject;
@Column(name = "always_permitted", columnDefinition = "boolean default false")
private boolean alwaysPermitted;
@Column(name = "category")
@ -364,6 +368,34 @@ public class OidcClient {
this.aliasAllowed = aliasAllowed;
}
/**
* @return the aliasQuota
*/
public boolean isAliasQuota() {
return aliasQuota;
}
/**
* @param aliasQuota the aliasQuota to set
*/
public void setAliasQuota(boolean aliasQuota) {
this.aliasQuota = aliasQuota;
}
/**
* @return the aliasSubject
*/
public boolean isAliasSubject() {
return aliasSubject;
}
/**
* @param aliasSubject the aliasSubject to set
*/
public void setAliasSubject(boolean aliasSubject) {
this.aliasSubject = aliasSubject;
}
/**
* Checks if is always permitted.
*