have export endpoint actually return a list of valid keys
Dynamically get a list of attributes to get the keys from, get their values, ensure they are in a valid format using a regex and finally return the list of keys as a JSON list. Co-authored-by: kritzl <kritzl@kritzl.dev>
This commit is contained in:
parent
e4b4497b30
commit
119a89f2ee
3 changed files with 50 additions and 21 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package de.ccc.hamburg.keycloak.ssh_key;
|
||||
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
|
@ -9,7 +9,8 @@ import org.keycloak.services.managers.AppAuthManager;
|
|||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
||||
import java.util.function.Function;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
|
||||
public class AuthHelper {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,37 @@
|
|||
package de.ccc.hamburg.keycloak.ssh_key;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.services.resource.RealmResourceProvider;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
public class SSHKeyResourceProvider implements RealmResourceProvider {
|
||||
private static final Logger LOG = Logger.getLogger(SSHKeyResourceProvider.class);
|
||||
private final KeycloakSession session;
|
||||
|
||||
// taken from: https://github.com/nemchik/ssh-key-regex
|
||||
private static final Pattern SSH_PUBLIC_KEY = Pattern.compile(
|
||||
"^(?<key>(ssh-dss AAAAB3NzaC1kc3|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzOD|ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1Mj|sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb2|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3})(\\s.*)?$");
|
||||
|
||||
public SSHKeyResourceProvider(KeycloakSession keycloakSession) {
|
||||
this.session = keycloakSession;
|
||||
}
|
||||
|
|
@ -40,26 +50,43 @@ public class SSHKeyResourceProvider implements RealmResourceProvider {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response exportKeys(@PathParam("group_id") String groupId) {
|
||||
UserProvider userProvider = session.users();
|
||||
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class);
|
||||
UPConfig upconfig = profileProvider.getConfiguration();
|
||||
|
||||
Stream<String> attributeNames = upconfig.getAttributes()
|
||||
.stream()
|
||||
.filter(a -> a.getGroup() != null && a.getGroup().equals("de.ccc.hamburg.keycloak.ssh_key.keys"))
|
||||
.map(a -> a.getName());
|
||||
|
||||
try {
|
||||
Auth auth = AuthHelper.getAuth(session,
|
||||
AuthHelper.getAuth(
|
||||
session,
|
||||
authResult -> authResult.getToken().getIssuedFor().equals("admin-cli"));
|
||||
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
|
||||
// TODO: add allowlist check
|
||||
GroupModel group = realm.getGroupById(groupId);
|
||||
|
||||
LOG.info(String.format("Getting Users from Group \"%s\" with ID %s", group.getName(), group.getId()));
|
||||
|
||||
Stream<UserModel> users = userProvider.getGroupMembersStream(realm, group);
|
||||
|
||||
users.forEach(user -> {
|
||||
String sshKey = user.getAttributeStream("ssh-key-1").findFirst().get();
|
||||
LOG.info(String.format("SSH Key of %s: %s", user.getUsername(), sshKey));
|
||||
});
|
||||
List<String> keys = users
|
||||
.map(user -> {
|
||||
return attributeNames
|
||||
.map(attributeName -> user.getAttributeStream(attributeName).findFirst())
|
||||
.filter(attribute -> attribute.isPresent())
|
||||
.map(attribute -> attribute.get())
|
||||
.toList();
|
||||
})
|
||||
.flatMap(List::stream)
|
||||
.map(key -> {
|
||||
final Matcher matcher = SSH_PUBLIC_KEY.matcher(key);
|
||||
return matcher.find() ? matcher.group("key") : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
|
||||
|
||||
return Response.ok(Map.of("hello", auth.getUser().getUsername())).build();
|
||||
return Response.ok(Map.of("keys", keys)).build();
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return Response.status(401, e.getMessage()).build();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package de.ccc.hamburg.keycloak.ssh_key;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.services.resource.RealmResourceProvider;
|
||||
import org.keycloak.services.resource.RealmResourceProviderFactory;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import org.keycloak.Config;
|
||||
|
||||
@AutoService(RealmResourceProviderFactory.class)
|
||||
public class SSHKeyResourceProviderFactory implements RealmResourceProviderFactory {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue