-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Protect custom resource with custom filter
- Loading branch information
Showing
5 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
.../src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/filter/AuthFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.github.thomasdarimont.keycloak.custom.endpoints.filter; | ||
|
||
import com.github.thomasdarimont.keycloak.custom.support.KeycloakSessionLookup; | ||
import jakarta.ws.rs.ForbiddenException; | ||
import jakarta.ws.rs.NotAuthorizedException; | ||
import jakarta.ws.rs.container.ContainerRequestContext; | ||
import jakarta.ws.rs.container.ContainerRequestFilter; | ||
import jakarta.ws.rs.ext.Provider; | ||
import org.keycloak.authorization.util.Tokens; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.representations.AccessToken; | ||
|
||
import java.io.IOException; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* Custom request filter for token handling. Executed if a request method is annotated with @FilterBinding | ||
*/ | ||
@Provider | ||
@AuthFilterBinding | ||
public class AuthFilter implements ContainerRequestFilter { | ||
|
||
private final KeycloakSession keycloakSession = KeycloakSessionLookup.currentSession(); | ||
|
||
private final Pattern clientPattern = Pattern.compile("acme.*"); | ||
|
||
@Override | ||
public void filter(ContainerRequestContext requestContext) throws IOException { | ||
// For some reason, the Authorization header is missing from the headers stored in keycloakSession | ||
String header = requestContext.getHeaderString("Authorization"); | ||
String token = null; | ||
|
||
if (header != null) { | ||
int index = header.indexOf("Bearer "); | ||
if (index >= 0) { | ||
token = header.substring(index + 7); | ||
} | ||
} | ||
|
||
AccessToken accessToken = Tokens.getAccessToken(token, keycloakSession); | ||
|
||
if (accessToken == null) { | ||
throw new NotAuthorizedException("Invalid or missing token"); | ||
} | ||
|
||
if (!clientPattern.matcher(accessToken.getIssuedFor()).matches()) { | ||
throw new ForbiddenException("This resource is only accessible for acme clients"); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...in/java/com/github/thomasdarimont/keycloak/custom/endpoints/filter/AuthFilterBinding.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.github.thomasdarimont.keycloak.custom.endpoints.filter; | ||
|
||
import jakarta.ws.rs.NameBinding; | ||
|
||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
|
||
@NameBinding | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface AuthFilterBinding { | ||
} |
30 changes: 30 additions & 0 deletions
30
...in/java/com/github/thomasdarimont/keycloak/custom/endpoints/filter/ProtectedResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.github.thomasdarimont.keycloak.custom.endpoints.filter; | ||
|
||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.core.Response; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Example for a resource protected by a request filter. | ||
* Methods annotated with @FilterBinding execute the filter before executing the method | ||
*/ | ||
public class ProtectedResource { | ||
|
||
@GET | ||
@Path("/protected") | ||
@AuthFilterBinding | ||
@Produces("application/json") | ||
public Response protectedResource() { | ||
return Response.ok(Map.of("secret", "opensesame")).build(); | ||
} | ||
|
||
@GET | ||
@Path("/protected") | ||
@Produces("application/json") | ||
public Response openResource() { | ||
return Response.ok(Map.of("public", "this is not a secret")).build(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...com/github/thomasdarimont/keycloak/custom/endpoints/filter/ProtectedResourceProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.github.thomasdarimont.keycloak.custom.endpoints.filter; | ||
|
||
import org.keycloak.services.resource.RealmResourceProvider; | ||
|
||
public class ProtectedResourceProvider implements RealmResourceProvider { | ||
|
||
@Override | ||
public Object getResource() { | ||
return new ProtectedResource(); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...hub/thomasdarimont/keycloak/custom/endpoints/filter/ProtectedResourceProviderFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.github.thomasdarimont.keycloak.custom.endpoints.filter; | ||
|
||
import com.google.auto.service.AutoService; | ||
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; | ||
|
||
|
||
@AutoService(RealmResourceProviderFactory.class) | ||
public class ProtectedResourceProviderFactory implements RealmResourceProviderFactory { | ||
@Override | ||
public RealmResourceProvider create(KeycloakSession session) { | ||
return new ProtectedResourceProvider(); | ||
} | ||
|
||
@Override | ||
public void init(Config.Scope config) { | ||
|
||
} | ||
|
||
@Override | ||
public void postInit(KeycloakSessionFactory factory) { | ||
|
||
} | ||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
|
||
@Override | ||
public String getId() { | ||
return "protected"; | ||
} | ||
} |