-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Use HTTP API for userli user lookup #22
Changes from 6 commits
d3eb79c
415bdb3
79ed89c
c18e370
da4865a
f5913cc
2c4a011
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,12 +24,36 @@ | |
<version>${version.keycloak}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-server-spi-private</artifactId> | ||
<version>${version.keycloak}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-services</artifactId> | ||
<version>${version.keycloak}</version> | ||
<scope>provided</scope> | ||
<exclusions> | ||
<exclusion> | ||
<groupId>org.jboss.resteasy</groupId> | ||
<artifactId>*</artifactId> | ||
</exclusion> | ||
</exclusions> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-model-jpa</artifactId> | ||
<version>${version.keycloak}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.httpcomponents</groupId> | ||
<artifactId>httpclient</artifactId> | ||
<version>4.5.14</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.jboss.logging</groupId> | ||
<artifactId>jboss-logging</artifactId> | ||
|
@@ -46,18 +70,27 @@ | |
<artifactId>resource-loader</artifactId> | ||
<version>2.0.2</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter-engine</artifactId> | ||
<version>5.10.2</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>1.18.32</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can also be removed as we need the logging only for development purposes. |
||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
<version>2.0.12</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-reload4j</artifactId> | ||
<version>2.0.12</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.rest-assured</groupId> | ||
<artifactId>rest-assured</artifactId> | ||
<version>5.4.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>jakarta.persistence</groupId> | ||
<artifactId>jakarta.persistence-api</artifactId> | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,10 @@ | ||||||||||||||
package org.systemli.keycloak; | ||||||||||||||
|
||||||||||||||
import lombok.experimental.UtilityClass; | ||||||||||||||
|
||||||||||||||
@UtilityClass | ||||||||||||||
public class Constants { | ||||||||||||||
public String REALM_DOMAIN = "userliRealmDomain"; | ||||||||||||||
public String BASE_URL = "userliBaseUrl"; | ||||||||||||||
public String KEYCLOAK_API_TOKEN = "userliKeycloakToken"; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Constants should be final to ensure they cannot be modified. |
||||||||||||||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.systemli.keycloak; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This interface only makes sense when we would expose an API in Keycloak, which we don't do. So this makes no sense here. |
||
|
||
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.PathParam; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.QueryParam; | ||
import jakarta.ws.rs.core.MediaType; | ||
|
||
import java.util.List; | ||
|
||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public interface UserliUserClient { | ||
|
||
@GET | ||
@Path("/api/keycloak/{domain}") | ||
List<UserliUser> getUsers(@QueryParam("search") String search, @QueryParam("first") int first, @QueryParam("max") int max); | ||
|
||
@GET | ||
@Path("/api/keycloak/{domain}/count") | ||
Integer getUsersCount(); | ||
|
||
@GET | ||
@Path("/api/keycloak/{domain}/user/{id}") | ||
UserliUser getUserById(@PathParam("id") String id); | ||
|
||
@POST | ||
@Path("/api/keycloak/{domain}/validate/${email}") | ||
Boolean validate(@PathParam("email") String email, @QueryParam("password") String password); | ||
|
||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,83 @@ | ||||
package org.systemli.keycloak; | ||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference; | ||||
import jakarta.ws.rs.WebApplicationException; | ||||
import jakarta.ws.rs.core.Response; | ||||
import lombok.SneakyThrows; | ||||
import lombok.extern.slf4j.Slf4j; | ||||
import org.apache.http.impl.client.CloseableHttpClient; | ||||
import org.keycloak.broker.provider.util.SimpleHttp; | ||||
import org.keycloak.component.ComponentModel; | ||||
import org.keycloak.connections.httpclient.HttpClientProvider; | ||||
import org.keycloak.models.KeycloakSession; | ||||
|
||||
import java.util.List; | ||||
|
||||
@Slf4j | ||||
public class UserliUserClientSimpleHttp implements UserliUserClient { | ||||
|
||||
private final CloseableHttpClient httpClient; | ||||
private final String realmDomain; | ||||
private final String baseUrl; | ||||
private final String keycloakApiToken; | ||||
|
||||
public UserliUserClientSimpleHttp(KeycloakSession session, ComponentModel model) { | ||||
this.httpClient = session.getProvider(HttpClientProvider.class).getHttpClient(); | ||||
this.realmDomain = model.get(Constants.REALM_DOMAIN); | ||||
this.baseUrl = model.get(Constants.BASE_URL); | ||||
this.keycloakApiToken = model.get(Constants.KEYCLOAK_API_TOKEN); | ||||
} | ||||
|
||||
@Override | ||||
@SneakyThrows | ||||
public List<UserliUser> getUsers(String search, int first, int max) { | ||||
String url = String.format("%s/api/keycloak/%s", baseUrl, realmDomain); | ||||
SimpleHttp simpleHttp = SimpleHttp.doGet(url, httpClient) | ||||
.auth(keycloakApiToken) | ||||
.param("first", String.valueOf(first)) | ||||
.param("max", String.valueOf(max)); | ||||
if (search != null) { | ||||
simpleHttp.param("search", search); | ||||
} | ||||
return simpleHttp.asJson(new TypeReference<>() {}); | ||||
} | ||||
|
||||
@Override | ||||
@SneakyThrows | ||||
public Integer getUsersCount() { | ||||
String url = String.format("%s/api/keycloak/%s/count", baseUrl, realmDomain); | ||||
String count = SimpleHttp.doGet(url, httpClient) | ||||
.auth(keycloakApiToken) | ||||
.asString(); | ||||
return Integer.valueOf(count); | ||||
} | ||||
|
||||
@Override | ||||
@SneakyThrows | ||||
public UserliUser getUserById(String id) { | ||||
String url = String.format("%s/api/keycloak/%s/user/%s", baseUrl, realmDomain, id); | ||||
SimpleHttp.Response response = SimpleHttp.doGet(url, httpClient) | ||||
.auth(keycloakApiToken) | ||||
.asResponse(); | ||||
if (response.getStatus() == 404) { | ||||
throw new WebApplicationException(response.getStatus()); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This exception is the only reason why we still need the Jakarta package. So I would recommend creating an exception on our own. |
||||
} | ||||
return response.asJson(UserliUser.class); | ||||
} | ||||
|
||||
@Override | ||||
@SneakyThrows | ||||
public Boolean validate(String email, String password) { | ||||
log.warn("UserliUserClientSimpleHttp validate: User with email '{}' and password '{}' tries to login", email, password); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Security! :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha ouch, this was a debugging leftover 🙈 |
||||
String url = String.format("%s/api/keycloak/%s/validate/%s", baseUrl, realmDomain, email); | ||||
SimpleHttp.Response response = SimpleHttp.doPost(url, httpClient) | ||||
.auth(keycloakApiToken) | ||||
.param("password", password) | ||||
.asResponse(); | ||||
if (response.getStatus() == 200) { | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
|
||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These dependencies are not needed. Also, the Jakarta Sodium dependencies can be safely removed.