🚧 Add many endpoints
This commit is contained in:
parent
82ce9aab62
commit
cf0b994eed
8
pom.xml
8
pom.xml
@ -63,12 +63,16 @@
|
||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-jwt</artifactId>
|
||||
<groupId>io.smallrye</groupId>
|
||||
<artifactId>smallrye-jwt</artifactId>
|
||||
<version>4.6.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-jwt-build</artifactId>
|
||||
<version>3.32.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
|
||||
@ -10,13 +10,11 @@ import jakarta.inject.Inject;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ClientBootstrapper
|
||||
{
|
||||
@Inject
|
||||
ClientService clientService;
|
||||
|
||||
@Inject
|
||||
ClientRepo clientRepo;
|
||||
|
||||
@ -33,9 +31,11 @@ public class ClientBootstrapper
|
||||
Optional<ClientEntity> existingClient = clientRepo.findByRealmAndIdOptional(realm, bootstrap.getKey());
|
||||
if (existingClient.isEmpty())
|
||||
{
|
||||
String id = bootstrap.getKey();
|
||||
String name = bootstrap.getKey();
|
||||
Client client = bootstrap.getValue();
|
||||
ClientEntity entity = new ClientEntity().setId(id)
|
||||
ClientEntity entity = new ClientEntity()
|
||||
.setId(UUID.randomUUID().toString().replace("-", "").substring(0, 16))
|
||||
.setName(name)
|
||||
.setSecret(Credentials.resolve(client.secret()))
|
||||
.setRedirectURI(client.redirectURI())
|
||||
.setRealm(realm)
|
||||
|
||||
@ -9,6 +9,7 @@ import de.tavolio.realm.RealmEntity;
|
||||
import de.tavolio.realm.RealmService;
|
||||
import de.tavolio.realm.client.ClientEntity;
|
||||
import de.tavolio.realm.client.ClientService;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
@ -57,7 +58,7 @@ public class OidcResource
|
||||
public Response auth(@QueryParam("client_id") String clientId, @FormParam("email") String email, @FormParam("password") String password)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity client = clientService.findByIdAndRealm(clientId, realm);
|
||||
ClientEntity client = clientService.requireByIdAndRealm(clientId, realm);
|
||||
if (client != null)
|
||||
{
|
||||
String code = authorizationService.generateBySessionCreation(realmKey, clientId, new AuthorizationCreation(email, password));
|
||||
@ -66,9 +67,9 @@ public class OidcResource
|
||||
throw new BadRequestException();
|
||||
}
|
||||
|
||||
@Authenticated
|
||||
@POST
|
||||
@Path("/token")
|
||||
@RolesAllowed("CLIENT")
|
||||
@Transactional
|
||||
public TokenResponse token(@FormParam("grant_type") String grantType, @FormParam("code") String code) throws NoSuchAlgorithmException, InvalidKeySpecException
|
||||
{
|
||||
|
||||
@ -39,7 +39,7 @@ public class AuthorizationService
|
||||
{
|
||||
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity client = clientService.findByIdAndRealm(clientId, realm);
|
||||
ClientEntity client = clientService.requireByIdAndRealm(clientId, realm);
|
||||
Optional<UserEntity> accountEntityOptional = userRepo.findOptionalByRealmAndEmail(realm, authorizationCreation.email());
|
||||
if (accountEntityOptional.isPresent())
|
||||
{
|
||||
|
||||
@ -12,9 +12,7 @@ import de.tavolio.realm.key.KeypairEntity;
|
||||
import de.tavolio.realm.key.KeypairRepo;
|
||||
import de.tavolio.realm.user.Permission;
|
||||
import de.tavolio.verify.JwksService;
|
||||
import de.tavolio.verify.jwks.JwksKey;
|
||||
import io.quarkus.security.AuthenticationFailedException;
|
||||
import io.quarkus.security.StringPermission;
|
||||
import io.quarkus.security.identity.AuthenticationRequestContext;
|
||||
import io.quarkus.security.identity.IdentityProvider;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
@ -36,7 +34,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ApplicationScoped
|
||||
@Priority(1)
|
||||
@ -82,7 +79,7 @@ public class ClientIdentityProvider implements IdentityProvider<TokenAuthenticat
|
||||
try
|
||||
{
|
||||
JsonWebToken token = new DefaultJWTParser(getContextForRealm(realm.getKey())).verify(raw, publicKey);
|
||||
ClientEntity client = clientService.findByIdAndRealm(token.getName(), realm);
|
||||
ClientEntity client = clientService.requireByIdAndRealm(token.getName(), realm);
|
||||
if (client != null)
|
||||
{
|
||||
Set<Permission> permissions = new HashSet<>(client.getPermissions());
|
||||
|
||||
@ -11,9 +11,7 @@ import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@ApplicationScoped
|
||||
@ -34,7 +32,7 @@ public class ClientTokenService
|
||||
public TokenResponse getToken(String realmKey)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity client = clientService.findByIdAndRealm(identity.getPrincipal().getName(), realm);
|
||||
ClientEntity client = clientService.requireByIdAndRealm(identity.getPrincipal().getName(), realm);
|
||||
if (client != null)
|
||||
{
|
||||
KeypairEntity keypair = realm.getKeys().getFirst();
|
||||
|
||||
@ -6,6 +6,7 @@ import io.quarkus.security.ForbiddenException;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ -15,8 +16,15 @@ public class PermissionService
|
||||
@Inject
|
||||
SecurityIdentity identity;
|
||||
|
||||
@ConfigProperty(name = "quarkus.profile")
|
||||
String profile;
|
||||
|
||||
public void hasPermission(Permission... required)
|
||||
{
|
||||
if ("dev".equals(profile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (identity.hasRole(Role.ROOT.toString()))
|
||||
{
|
||||
return;
|
||||
|
||||
@ -7,6 +7,8 @@ import de.tavolio.realm.client.ClientEntity;
|
||||
import de.tavolio.realm.code.CodeEntity;
|
||||
import de.tavolio.realm.role.RoleEntity;
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -16,29 +18,49 @@ import java.util.List;
|
||||
public class RealmEntity
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private String id;
|
||||
|
||||
private String key;
|
||||
|
||||
@Column(name = "realm_name")
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "realm", cascade = CascadeType.ALL)
|
||||
@OneToMany(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<KeypairEntity> keys = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<UserEntity> accounts = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<ClientEntity> clients = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<CodeEntity> codes = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<RoleEntity> roles = new ArrayList<>();
|
||||
|
||||
@OneToOne(mappedBy = "realm")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private AudienceStrategyEntity audienceStrategy;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public RealmEntity setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getKey()
|
||||
{
|
||||
return key;
|
||||
|
||||
@ -1,35 +1,68 @@
|
||||
package de.tavolio.realm;
|
||||
|
||||
import de.tavolio.Role;
|
||||
import de.tavolio.oidc.OidcConfigurationResource;
|
||||
import de.tavolio.oidc.OidcResource;
|
||||
import de.tavolio.realm.client.ClientResource;
|
||||
import de.tavolio.realm.role.RoleResource;
|
||||
import de.tavolio.realm.user.UserResource;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.enterprise.inject.spi.CDI;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
||||
@Path("/realms/{realm-key}")
|
||||
import java.util.List;
|
||||
|
||||
@Path("/realms")
|
||||
public class RealmResource
|
||||
{
|
||||
@Path("/")
|
||||
@Inject
|
||||
RealmRepo repo;
|
||||
|
||||
@Path("/{realm-key}")
|
||||
public RealmSubResource realms()
|
||||
{
|
||||
return CDI.current().select(RealmSubResource.class).get();
|
||||
}
|
||||
|
||||
@Path("/accounts")
|
||||
@RolesAllowed("ROOT")
|
||||
@Path("/{realm-key}/users")
|
||||
public UserResource accounts()
|
||||
{
|
||||
return CDI.current().select(UserResource.class).get();
|
||||
}
|
||||
|
||||
@Path("/protocol/openid-connect")
|
||||
@RolesAllowed("ROOT")
|
||||
@Path("/{realm-key}/clients")
|
||||
public ClientResource clients()
|
||||
{
|
||||
return CDI.current().select(ClientResource.class).get();
|
||||
}
|
||||
|
||||
@RolesAllowed("ROOT")
|
||||
@Path("/{realm-key}/roles")
|
||||
public RoleResource roles()
|
||||
{
|
||||
return CDI.current().select(RoleResource.class).get();
|
||||
}
|
||||
|
||||
@Path("/{realm-key}/protocol/openid-connect")
|
||||
public OidcResource oidc()
|
||||
{
|
||||
return CDI.current().select(OidcResource.class).get();
|
||||
}
|
||||
|
||||
@Path("/.well-known/openid-configuration")
|
||||
@Path("/{realm-key}/.well-known/openid-configuration")
|
||||
public OidcConfigurationResource oidcConfigurationResource()
|
||||
{
|
||||
return CDI.current().select(OidcConfigurationResource.class).get();
|
||||
}
|
||||
|
||||
@GET
|
||||
public List<Realm> get()
|
||||
{
|
||||
return repo.listAll().stream().map(item -> new Realm(item.getKey(), item.getName())).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public class RealmService
|
||||
|
||||
public RealmEntity requireByKey(String key)
|
||||
{
|
||||
RealmEntity realm = repo.findById(key);
|
||||
RealmEntity realm = repo.findByKey(key);
|
||||
if (realm != null)
|
||||
{
|
||||
return realm;
|
||||
|
||||
@ -1,25 +1,36 @@
|
||||
package de.tavolio.realm;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
@RequestScoped
|
||||
public class RealmSubResource
|
||||
{
|
||||
@PathParam("realm-key")
|
||||
String key;
|
||||
|
||||
@Inject
|
||||
RealmRepo repo;
|
||||
|
||||
@Inject
|
||||
RealmService service;
|
||||
|
||||
@GET
|
||||
public Realm get(@PathParam("realm-key") String key)
|
||||
public Realm get()
|
||||
{
|
||||
RealmEntity entity = repo.findById(key);
|
||||
if (entity != null)
|
||||
{
|
||||
return new Realm(entity.getKey(), entity.getName());
|
||||
}
|
||||
throw new NotFoundException();
|
||||
RealmEntity realm = service.requireByKey(key);
|
||||
return new Realm(realm.getKey(), realm.getName());
|
||||
}
|
||||
|
||||
@RolesAllowed("ROOT")
|
||||
@DELETE
|
||||
public void delete()
|
||||
{
|
||||
repo.delete(service.requireByKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
7
src/main/java/de/tavolio/realm/client/Client.java
Normal file
7
src/main/java/de/tavolio/realm/client/Client.java
Normal file
@ -0,0 +1,7 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public record Client(String id, String name, String redirectURI, Set<Grant> allowedGrants)
|
||||
{
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
public record ClientCreation(String id, String secret)
|
||||
import java.util.Set;
|
||||
|
||||
public record ClientCreation(String name, String secret, String redirectURI, Set<Grant> allowedGrants)
|
||||
{
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ public class ClientEntity implements RealmScoped
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String secret;
|
||||
|
||||
@Column(name = "redirect_uri")
|
||||
@ -32,12 +34,16 @@ public class ClientEntity implements RealmScoped
|
||||
private List<CodeEntity> codes;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "client_permission",
|
||||
joinColumns = @JoinColumn(name = "client_id")
|
||||
)
|
||||
@CollectionTable(name = "client_permission", joinColumns = @JoinColumn(name = "client_id"))
|
||||
@Column(name = "permission")
|
||||
private Set<String> permissions = new HashSet<>();
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Set<Permission> permissions = new HashSet<>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "allowed_grants", joinColumns = @JoinColumn(name = "client_id"))
|
||||
@Column(name = "grant_name")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Set<Grant> allowedGrants = new HashSet<Grant>();
|
||||
|
||||
public String getId()
|
||||
{
|
||||
@ -50,6 +56,17 @@ public class ClientEntity implements RealmScoped
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public ClientEntity setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSecret()
|
||||
{
|
||||
return secret;
|
||||
@ -96,12 +113,23 @@ public class ClientEntity implements RealmScoped
|
||||
|
||||
public Set<Permission> getPermissions()
|
||||
{
|
||||
return permissions.stream().map(Permission::valueOf).collect(Collectors.toSet());
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public ClientEntity setPermissions(Set<Permission> permissions)
|
||||
{
|
||||
this.permissions = permissions.stream().map(Enum::toString).collect(Collectors.toSet());
|
||||
this.permissions = permissions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<Grant> getAllowedGrants()
|
||||
{
|
||||
return allowedGrants;
|
||||
}
|
||||
|
||||
public ClientEntity setAllowedGrants(Set<Grant> allowedGrants)
|
||||
{
|
||||
this.allowedGrants = allowedGrants;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
16
src/main/java/de/tavolio/realm/client/ClientMapper.java
Normal file
16
src/main/java/de/tavolio/realm/client/ClientMapper.java
Normal file
@ -0,0 +1,16 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ClientMapper
|
||||
{
|
||||
public static List<Client> map(List<ClientEntity> client)
|
||||
{
|
||||
return client.stream().map(ClientMapper::map).toList();
|
||||
}
|
||||
|
||||
public static Client map(ClientEntity client)
|
||||
{
|
||||
return new Client(client.getId(), client.getName(), client.getRedirectURI(), client.getAllowedGrants());
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApplicationScoped
|
||||
@ -19,4 +20,14 @@ public class ClientRepo implements PanacheRepositoryBase<ClientEntity, String>
|
||||
{
|
||||
return find("realm = :realm AND id = :id", Parameters.with("realm", realm).and("id", id)).firstResult();
|
||||
}
|
||||
|
||||
public List<ClientEntity> findByRealm(RealmEntity realm)
|
||||
{
|
||||
return list("realm = :realm", Parameters.with("realm", realm));
|
||||
}
|
||||
|
||||
public ClientEntity findByRealmAndName(RealmEntity realm, String name)
|
||||
{
|
||||
return find("realm = :realm AND name = :name", Parameters.with("realm", realm).and("name", name)).firstResult();
|
||||
}
|
||||
}
|
||||
|
||||
54
src/main/java/de/tavolio/realm/client/ClientResource.java
Normal file
54
src/main/java/de/tavolio/realm/client/ClientResource.java
Normal file
@ -0,0 +1,54 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
import de.tavolio.realm.RealmEntity;
|
||||
import de.tavolio.realm.RealmService;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequestScoped
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ClientResource
|
||||
{
|
||||
@PathParam("realm-key")
|
||||
String realmKey;
|
||||
|
||||
@Inject
|
||||
ClientRepo repo;
|
||||
|
||||
@Inject
|
||||
ClientService clientService;
|
||||
|
||||
@Inject
|
||||
RealmService realmService;
|
||||
|
||||
@GET
|
||||
public List<Client> get()
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
return ClientMapper.map(repo.findByRealm(realm));
|
||||
}
|
||||
|
||||
@POST
|
||||
public Client post(ClientCreation creation)
|
||||
{
|
||||
return clientService.create(realmKey, creation);
|
||||
}
|
||||
|
||||
@Path("/{client-name}")
|
||||
@PUT
|
||||
public Client put(@PathParam("client-name") String clientName, Client client)
|
||||
{
|
||||
return clientService.update(realmKey, clientName, client);
|
||||
}
|
||||
|
||||
@Path("/{client-name}")
|
||||
@DELETE
|
||||
public void delete(@PathParam("client-name") String clientName)
|
||||
{
|
||||
clientService.delete(realmKey, clientName);
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,17 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
import de.tavolio.bootstrap.Credentials;
|
||||
import de.tavolio.bootstrap.model.Client;
|
||||
import de.tavolio.realm.RealmEntity;
|
||||
import de.tavolio.realm.RealmRepo;
|
||||
import de.tavolio.realm.RealmService;
|
||||
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ClientService
|
||||
@ -20,9 +20,9 @@ public class ClientService
|
||||
ClientRepo clientRepo;
|
||||
|
||||
@Inject
|
||||
RealmRepo realmRepo;
|
||||
RealmService realmService;
|
||||
|
||||
public ClientEntity findByIdAndRealm(String clientId, RealmEntity realm)
|
||||
public ClientEntity requireByIdAndRealm(String clientId, RealmEntity realm)
|
||||
{
|
||||
ClientEntity client = clientRepo.findByRealmAndId(realm, clientId);
|
||||
if (client != null)
|
||||
@ -33,17 +33,46 @@ public class ClientService
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ClientEntity create(String realmKey, ClientCreation client)
|
||||
public Client create(String realmKey, ClientCreation client)
|
||||
{
|
||||
RealmEntity realm = realmRepo.findByKey(realmKey);
|
||||
if (realm != null)
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity entity = new ClientEntity();
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", "").substring(0, 16));
|
||||
entity.setName(client.name());
|
||||
if (!StringUtils.isBlank(client.secret()))
|
||||
{
|
||||
ClientEntity entity = new ClientEntity();
|
||||
entity.setId(client.id());
|
||||
entity.setSecret(BcryptUtil.bcryptHash(client.secret()));
|
||||
entity.setRealm(realm);
|
||||
clientRepo.persist(entity);
|
||||
return entity;
|
||||
}
|
||||
entity.setAllowedGrants(client.allowedGrants());
|
||||
entity.setRedirectURI(client.redirectURI());
|
||||
entity.setRealm(realm);
|
||||
clientRepo.persist(entity);
|
||||
return ClientMapper.map(entity);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delete(String realmKey, String clientName)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity client = clientRepo.findByRealmAndName(realm, clientName);
|
||||
if (client != null)
|
||||
{
|
||||
clientRepo.delete(client);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Client update(String realmKey, String clientName, Client client)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
ClientEntity existing = clientRepo.findByRealmAndName(realm, clientName);
|
||||
if (existing != null)
|
||||
{
|
||||
existing.setName(client.name());
|
||||
existing.setRedirectURI(client.redirectURI());
|
||||
existing.setAllowedGrants(client.allowedGrants());
|
||||
clientRepo.persist(existing);
|
||||
return ClientMapper.map(existing);
|
||||
}
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
6
src/main/java/de/tavolio/realm/client/Grant.java
Normal file
6
src/main/java/de/tavolio/realm/client/Grant.java
Normal file
@ -0,0 +1,6 @@
|
||||
package de.tavolio.realm.client;
|
||||
|
||||
public enum Grant
|
||||
{
|
||||
CLIENT_CREDENTIALS, AUTHORIZATION, PASSWORD
|
||||
}
|
||||
5
src/main/java/de/tavolio/realm/role/Role.java
Normal file
5
src/main/java/de/tavolio/realm/role/Role.java
Normal file
@ -0,0 +1,5 @@
|
||||
package de.tavolio.realm.role;
|
||||
|
||||
public record Role(String id, String name)
|
||||
{
|
||||
}
|
||||
5
src/main/java/de/tavolio/realm/role/RoleCreation.java
Normal file
5
src/main/java/de/tavolio/realm/role/RoleCreation.java
Normal file
@ -0,0 +1,5 @@
|
||||
package de.tavolio.realm.role;
|
||||
|
||||
public record RoleCreation(String name)
|
||||
{
|
||||
}
|
||||
@ -21,14 +21,6 @@ public class RoleEntity implements RealmScoped
|
||||
@JoinColumn(name = "realm_id")
|
||||
private RealmEntity realm;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "permission",
|
||||
joinColumns = @JoinColumn(name = "role_id")
|
||||
)
|
||||
@Column(name = "permission")
|
||||
private List<String> permissions = new ArrayList<>();
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
@ -51,17 +43,6 @@ public class RoleEntity implements RealmScoped
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getPermissions()
|
||||
{
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public RoleEntity setPermissions(List<String> permissions)
|
||||
{
|
||||
this.permissions = permissions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RealmEntity getRealm()
|
||||
{
|
||||
return realm;
|
||||
@ -72,16 +53,4 @@ public class RoleEntity implements RealmScoped
|
||||
this.realm = realm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String permission)
|
||||
{
|
||||
for (String value : permissions)
|
||||
{
|
||||
if (permission.equals(value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,13 +5,14 @@ import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApplicationScoped
|
||||
public class RoleRepo implements PanacheRepositoryBase<RoleEntity, String>
|
||||
{
|
||||
public Optional<RoleEntity> findByNameAndRealmOptional(String name, RealmEntity realm)
|
||||
public List<RoleEntity> findByRealm(RealmEntity realm)
|
||||
{
|
||||
return find("realm = :realm AND name = :name", Parameters.with("realm", realm).and("name", name)).firstResultOptional();
|
||||
return list("realm = :realm", Parameters.with("realm", realm));
|
||||
}
|
||||
}
|
||||
|
||||
31
src/main/java/de/tavolio/realm/role/RoleResource.java
Normal file
31
src/main/java/de/tavolio/realm/role/RoleResource.java
Normal file
@ -0,0 +1,31 @@
|
||||
package de.tavolio.realm.role;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequestScoped
|
||||
public class RoleResource
|
||||
{
|
||||
@PathParam("realm-key")
|
||||
String realmKey;
|
||||
|
||||
@Inject
|
||||
RoleService roleService;
|
||||
|
||||
@GET
|
||||
public List<Role> get()
|
||||
{
|
||||
return roleService.findByRealm(realmKey);
|
||||
}
|
||||
|
||||
@POST
|
||||
public Role post(RoleCreation creation)
|
||||
{
|
||||
return roleService.create(realmKey, creation);
|
||||
}
|
||||
}
|
||||
50
src/main/java/de/tavolio/realm/role/RoleService.java
Normal file
50
src/main/java/de/tavolio/realm/role/RoleService.java
Normal file
@ -0,0 +1,50 @@
|
||||
package de.tavolio.realm.role;
|
||||
|
||||
import de.tavolio.realm.RealmEntity;
|
||||
import de.tavolio.realm.RealmResource;
|
||||
import de.tavolio.realm.RealmService;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ApplicationScoped
|
||||
public class RoleService
|
||||
{
|
||||
@Inject
|
||||
RoleRepo repo;
|
||||
|
||||
@Inject
|
||||
RealmService realmService;
|
||||
|
||||
@Transactional
|
||||
public Role create(String realmKey, RoleCreation roleCreation)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
|
||||
RoleEntity role = new RoleEntity();
|
||||
role.setId(UUID.randomUUID().toString());
|
||||
role.setName(roleCreation.name());
|
||||
role.setRealm(realm);
|
||||
repo.persist(role);
|
||||
return map(role);
|
||||
}
|
||||
|
||||
public List<Role> findByRealm(String realmKey)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
return map(repo.findByRealm(realm));
|
||||
}
|
||||
|
||||
private List<Role> map(List<RoleEntity> entities)
|
||||
{
|
||||
return entities.stream().map(this::map).toList();
|
||||
}
|
||||
|
||||
private Role map(RoleEntity entity)
|
||||
{
|
||||
return new Role(entity.getId(), entity.getName());
|
||||
}
|
||||
}
|
||||
@ -20,4 +20,14 @@ public class UserRepo implements PanacheRepositoryBase<UserEntity, String>
|
||||
{
|
||||
return list("id IN :ids", Parameters.with("ids", ids));
|
||||
}
|
||||
|
||||
public List<UserEntity> findByRealm(RealmEntity realm)
|
||||
{
|
||||
return list("realm = :realm", Parameters.with("realm", realm));
|
||||
}
|
||||
|
||||
public UserEntity findByRealmAndId(RealmEntity realm, String id)
|
||||
{
|
||||
return find("realm = :realm AND id = :id", Parameters.with("realm", realm).and("id", id)).firstResult();
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,10 +6,7 @@ import de.tavolio.realm.user.dto.UserCreation;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.*;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.List;
|
||||
@ -41,7 +38,7 @@ public class UserResource
|
||||
public List<User> get()
|
||||
{
|
||||
permissionService.hasPermission(Permission.USER_VIEW);
|
||||
return userService.get();
|
||||
return userService.get(realmKey);
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -52,6 +49,14 @@ public class UserResource
|
||||
return userService.getUser(id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public void delete(@PathParam("id") String id)
|
||||
{
|
||||
permissionService.hasPermission(Permission.USER_VIEW);
|
||||
userService.delete(realmKey, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/search")
|
||||
public Map<String, User> get(List<String> ids)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package de.tavolio.realm.user;
|
||||
|
||||
import de.tavolio.AuthenticationService;
|
||||
import de.tavolio.realm.RealmService;
|
||||
import de.tavolio.realm.user.dto.User;
|
||||
import de.tavolio.realm.user.dto.UserCreation;
|
||||
import de.tavolio.realm.RealmEntity;
|
||||
@ -35,6 +36,9 @@ public class UserService
|
||||
@Inject
|
||||
RealmRepo realmRepo;
|
||||
|
||||
@Inject
|
||||
RealmService realmService;
|
||||
|
||||
@Transactional
|
||||
public User create(String realmId, UserCreation account)
|
||||
{
|
||||
@ -54,21 +58,15 @@ public class UserService
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
public List<User> get()
|
||||
public List<User> get(String realmKey)
|
||||
{
|
||||
return userMapper.map(userRepo.listAll());
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
return userMapper.map(userRepo.findByRealm(realm));
|
||||
}
|
||||
|
||||
public User getUser(String id)
|
||||
{
|
||||
UserEntity account = authenticationService.requireUser();
|
||||
UserEntity requestedAccount = userRepo.findById(id);
|
||||
if (requestedAccount != null && requestedAccount.getId().equals(account.getId()))
|
||||
{
|
||||
return userMapper.map(authenticationService.requireUser());
|
||||
}
|
||||
LOG.errorf("Cannot access account");
|
||||
throw new UnauthorizedException();
|
||||
return userMapper.map(userRepo.findById(id));
|
||||
}
|
||||
|
||||
public Map<String, User> findByIds(List<String> ids)
|
||||
@ -80,4 +78,15 @@ public class UserService
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delete(String realmKey, String id)
|
||||
{
|
||||
RealmEntity realm = realmService.requireByKey(realmKey);
|
||||
UserEntity user = userRepo.findByRealmAndId(realm, id);
|
||||
if (user != null)
|
||||
{
|
||||
userRepo.delete(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
realms:
|
||||
maven:
|
||||
name: MavenVault
|
||||
lifetime: 3600
|
||||
audience:
|
||||
strategy: static
|
||||
value: https://maven.dinauer.dev/api
|
||||
@ -14,6 +15,12 @@ realms:
|
||||
redirect-uri: http://localhost:8080/callback
|
||||
permissions:
|
||||
- USER_VIEW
|
||||
analytics-backend:
|
||||
secret:
|
||||
bcrypt: $2a$12$1oYS45e/nXP1OeMgdZZAKeEixarRDzbBGZd0xOnEQQMKlOKwVMrX.
|
||||
redirect-uri: http://localhost:8080/callback
|
||||
permissions:
|
||||
- USER_VIEW
|
||||
users:
|
||||
- email: andreas.j.dinauer@gmail.com
|
||||
first-name: Andreas
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user