proxy headers
This commit is contained in:
parent
e14c5adf55
commit
7d4f28f52d
4 changed files with 77 additions and 6 deletions
|
@ -274,4 +274,46 @@ $ java -jar bin/launcher.jar [your-config.json]
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Keycloak Identity Headers</title>
|
||||||
|
<para>
|
||||||
|
When forwarding requests to the proxied server, Keycloak Proxy will set some additional headers with values from the
|
||||||
|
OIDC identity token it received for authentication.
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>KEYCLOAK_SUBJECT</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
User id. Corresponds to JWT <literal>sub</literal> and will be the user id Keycloak uses to store
|
||||||
|
this user.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>KEYCLOAK_USERNAME</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Username. Corresponds to JWT <literal>preferred_username</literal>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>KEYCLOAK_EMAIL</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Email address of user if set.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>KEYCLOAK_NAME</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Full name of user if set.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
</chapter>
|
</chapter>
|
4
pom.xml
4
pom.xml
|
@ -18,8 +18,8 @@
|
||||||
<keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
|
<keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
|
||||||
<resteasy.version>2.3.7.Final</resteasy.version>
|
<resteasy.version>2.3.7.Final</resteasy.version>
|
||||||
<resteasy.version.latest>3.0.9.Final</resteasy.version.latest>
|
<resteasy.version.latest>3.0.9.Final</resteasy.version.latest>
|
||||||
|
<!-- <undertow.version>1.1.0.Final</undertow.version> -->
|
||||||
<undertow.version>1.0.15.Final</undertow.version>
|
<undertow.version>1.0.15.Final</undertow.version>
|
||||||
<!-- <picketlink.version>2.7.0.CR1-20140924</picketlink.version> -->
|
|
||||||
<picketlink.version>2.7.0.CR2</picketlink.version>
|
<picketlink.version>2.7.0.CR2</picketlink.version>
|
||||||
<picketbox.ldap.version>1.0.2.Final</picketbox.ldap.version>
|
<picketbox.ldap.version>1.0.2.Final</picketbox.ldap.version>
|
||||||
<mongo.driver.version>2.11.3</mongo.driver.version>
|
<mongo.driver.version>2.11.3</mongo.driver.version>
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
<module>events</module>
|
<module>events</module>
|
||||||
<module>model</module>
|
<module>model</module>
|
||||||
<module>integration</module>
|
<module>integration</module>
|
||||||
<module>proxy</module>
|
<module>proxy/proxy-server</module>
|
||||||
<module>picketlink</module>
|
<module>picketlink</module>
|
||||||
<module>federation</module>
|
<module>federation</module>
|
||||||
<module>services</module>
|
<module>services</module>
|
||||||
|
|
|
@ -2,7 +2,9 @@ package org.keycloak.proxy;
|
||||||
|
|
||||||
import io.undertow.server.HttpHandler;
|
import io.undertow.server.HttpHandler;
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
|
import io.undertow.util.HttpString;
|
||||||
import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
|
import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@ -11,6 +13,10 @@ import java.util.Collection;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class ConstraintAuthorizationHandler implements HttpHandler {
|
public class ConstraintAuthorizationHandler implements HttpHandler {
|
||||||
|
public static final HttpString KEYCLOAK_SUBJECT = new HttpString("KEYCLOAK_SUBJECT");
|
||||||
|
public static final HttpString KEYCLOAK_USERNAME = new HttpString("KEYCLOAK_USERNAME");
|
||||||
|
public static final HttpString KEYCLOAK_EMAIL = new HttpString("KEYCLOAK_EMAIL");
|
||||||
|
public static final HttpString KEYCLOAK_NAME = new HttpString("KEYCLOAK_NAME");
|
||||||
|
|
||||||
protected HttpHandler next;
|
protected HttpHandler next;
|
||||||
protected String errorPage;
|
protected String errorPage;
|
||||||
|
@ -25,13 +31,13 @@ public class ConstraintAuthorizationHandler implements HttpHandler {
|
||||||
KeycloakUndertowAccount account = (KeycloakUndertowAccount)exchange.getSecurityContext().getAuthenticatedAccount();
|
KeycloakUndertowAccount account = (KeycloakUndertowAccount)exchange.getSecurityContext().getAuthenticatedAccount();
|
||||||
SingleConstraintMatch match = exchange.getAttachment(ConstraintMatcherHandler.CONSTRAINT_KEY);
|
SingleConstraintMatch match = exchange.getAttachment(ConstraintMatcherHandler.CONSTRAINT_KEY);
|
||||||
if (match == null || (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.AUTHENTICATE)) {
|
if (match == null || (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.AUTHENTICATE)) {
|
||||||
next.handleRequest(exchange);
|
authenticatedRequest(account, exchange);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
for (String role : match.getRequiredRoles()) {
|
for (String role : match.getRequiredRoles()) {
|
||||||
if (account.getRoles().contains(role)) {
|
if (account.getRoles().contains(role)) {
|
||||||
next.handleRequest(exchange);
|
authenticatedRequest(account, exchange);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,4 +54,23 @@ public class ConstraintAuthorizationHandler implements HttpHandler {
|
||||||
exchange.endExchange();
|
exchange.endExchange();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void authenticatedRequest(KeycloakUndertowAccount account, HttpServerExchange exchange) throws Exception {
|
||||||
|
if (account != null) {
|
||||||
|
IDToken idToken = account.getKeycloakSecurityContext().getIdToken();
|
||||||
|
if (idToken.getSubject() != null) {
|
||||||
|
exchange.getRequestHeaders().put(KEYCLOAK_SUBJECT, idToken.getSubject());
|
||||||
|
}
|
||||||
|
if (idToken.getPreferredUsername() != null) {
|
||||||
|
exchange.getRequestHeaders().put(KEYCLOAK_USERNAME, idToken.getPreferredUsername());
|
||||||
|
}
|
||||||
|
if (idToken.getEmail() != null) {
|
||||||
|
exchange.getRequestHeaders().put(KEYCLOAK_EMAIL, idToken.getEmail());
|
||||||
|
}
|
||||||
|
if (idToken.getName() != null) {
|
||||||
|
exchange.getRequestHeaders().put(KEYCLOAK_NAME, idToken.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.handleRequest(exchange);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,8 +101,11 @@ public class ProxyTest {
|
||||||
req.getSession().setAttribute("counter", new Integer(count.intValue() + 1));
|
req.getSession().setAttribute("counter", new Integer(count.intValue() + 1));
|
||||||
stream.write(("count:"+count).getBytes());
|
stream.write(("count:"+count).getBytes());
|
||||||
|
|
||||||
|
Enumeration<String> headers = req.getHeaderNames();
|
||||||
|
while (headers.hasMoreElements()) {
|
||||||
|
String name = headers.nextElement();
|
||||||
|
System.out.println(name +": " + req.getHeader(name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
Loading…
Reference in a new issue