KEYCLOAK-1295 Adapter support. Fixes

This commit is contained in:
mposolda committed 2015-08-21 08:26:12 +02:00
1 parent 87f7ec5909
commit d8d6348f67
64 files changed
+915 -661

No files matched your search

@@ -0,0 +1,19 @@
package org.keycloak.example;
/**
* Client authentication with traditional OAuth2 client_id + client_secret
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ProductSAClientSecretServlet extends ProductServiceAccountServlet {
@Override
protected String getAdapterConfigLocation() {
return "WEB-INF/keycloak-client-secret.json";
}
@Override
protected String getClientAuthenticationMethod() {
return "secret";
}
}
@@ -0,0 +1,17 @@
package org.keycloak.example;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ProductSAClientSignedJWTServlet extends ProductServiceAccountServlet {
@Override
protected String getAdapterConfigLocation() {
return "WEB-INF/keycloak-client-signed-jwt.json";
}
@Override
protected String getClientAuthenticationMethod() {
return "jwt";
}
}
@@ -4,7 +4,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -26,30 +28,46 @@ import org.keycloak.VerificationException;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.constants.ServiceAccountConstants;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ProductServiceAccountServlet extends HttpServlet {
public abstract class ProductServiceAccountServlet extends HttpServlet {
public static final String ERROR = "error";
public static final String TOKEN = "token";
public static final String TOKEN_PARSED = "idTokenParsed";
public static final String REFRESH_TOKEN = "refreshToken";
public static final String PRODUCTS = "products";
public static final String CLIENT_AUTH_METHOD = "clientAuthMethod";
protected abstract String getAdapterConfigLocation();
protected abstract String getClientAuthenticationMethod();
public static String getLoginUrl(HttpServletRequest request) {
return "/service-account-portal/app-" + request.getAttribute(CLIENT_AUTH_METHOD) + "/login";
}
public static String getRefreshUrl(HttpServletRequest request) {
return "/service-account-portal/app-" + request.getAttribute(CLIENT_AUTH_METHOD) + "/refresh";
}
public static String getLogoutUrl(HttpServletRequest request) {
return "/service-account-portal/app-" + request.getAttribute(CLIENT_AUTH_METHOD) + "/logout";
}
@Override
public void init() throws ServletException {
InputStream config = getServletContext().getResourceAsStream("WEB-INF/keycloak.json");
String adapterConfigLocation = getAdapterConfigLocation();
InputStream config = getServletContext().getResourceAsStream(adapterConfigLocation);
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(config);
HttpClient client = new DefaultHttpClient();
getServletContext().setAttribute("deployment-" + getClientAuthenticationMethod(), deployment);
getServletContext().setAttribute(KeycloakDeployment.class.getName(), deployment);
HttpClient client = new DefaultHttpClient();
getServletContext().setAttribute(HttpClient.class.getName(), client);
}
@@ -60,6 +78,8 @@ public class ProductServiceAccountServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute(CLIENT_AUTH_METHOD, getClientAuthenticationMethod());
String reqUri = req.getRequestURI();
if (reqUri.endsWith("/login")) {
serviceAccountLogin(req);
@@ -81,16 +101,21 @@ public class ProductServiceAccountServlet extends HttpServlet {
KeycloakDeployment deployment = getKeycloakDeployment();
HttpClient client = getHttpClient();
String clientId = deployment.getResourceName();
String clientSecret = deployment.getResourceCredentials().get("secret");
try {
HttpPost post = new HttpPost(deployment.getTokenUrl());
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
String authHeader = BasicAuthHelper.createHeader(clientId, clientSecret);
post.addHeader("Authorization", authHeader);
// Add client credentials according to the method configured in keycloak.json file
Map<String, String> reqHeaders = new HashMap<>();
Map<String, String> reqParams = new HashMap<>();
ClientCredentialsProviderUtils.setClientCredentials(deployment, reqHeaders, reqParams);
for (Map.Entry<String, String> header : reqHeaders.entrySet()) {
post.setHeader(header.getKey(), header.getValue());
}
for (Map.Entry<String, String> param : reqParams.entrySet()) {
formparams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
@@ -217,7 +242,7 @@ public class ProductServiceAccountServlet extends HttpServlet {
}
private KeycloakDeployment getKeycloakDeployment() {
return (KeycloakDeployment) getServletContext().getAttribute(KeycloakDeployment.class.getName());
return (KeycloakDeployment) getServletContext().getAttribute("deployment-" + getClientAuthenticationMethod());
}
private HttpClient getHttpClient() {
@@ -0,0 +1,17 @@
{
"realm" : "demo",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url" : "http://localhost:8080/auth",
"ssl-required" : "external",
"resource" : "product-sa-client",
"credentials": {
"jwt": {
"client-keystore-file": "classpath:keystore-client.jks",
"client-keystore-type": "JKS",
"client-keystore-password": "storepass",
"client-key-password": "keypass",
"client-key-alias": "clientkey",
"token-expiration": 10
}
}
}
@@ -13,10 +13,16 @@
AccessToken token = (AccessToken) request.getSession().getAttribute(ProductServiceAccountServlet.TOKEN_PARSED);
String products = (String) request.getAttribute(ProductServiceAccountServlet.PRODUCTS);
String appError = (String) request.getAttribute(ProductServiceAccountServlet.ERROR);
String clientAuthMethod = (String) request.getAttribute(ProductServiceAccountServlet.CLIENT_AUTH_METHOD);
String loginUrl = ProductServiceAccountServlet.getLoginUrl(request);
String refreshUrl = ProductServiceAccountServlet.getRefreshUrl(request);
String logoutUrl = ProductServiceAccountServlet.getLogoutUrl(request);
%>
<h1>Service account portal</h1>
<p><a href="/service-account-portal/app/login">Login</a> | <a href="/service-account-portal/app/refresh">Refresh token</a> | <a
href="/service-account-portal/app/logout">Logout</a></p>
<h2>Client authentication method: <%= clientAuthMethod %></h2>
<p><a href="<%= loginUrl %>">Login</a> | <a href="<%= refreshUrl %>">Refresh token</a> | <a
href="<%= logoutUrl %>">Logout</a></p>
<hr />
<% if (appError != null) { %>
@@ -7,13 +7,23 @@
<module-name>service-account-portal</module-name>
<servlet>
<servlet-name>ServiceAccountExample</servlet-name>
<servlet-class>org.keycloak.example.ProductServiceAccountServlet</servlet-class>
<servlet-name>ProductSAClientSecretServlet</servlet-name>
<servlet-class>org.keycloak.example.ProductSAClientSecretServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ProductSAClientSignedJWTServlet</servlet-name>
<servlet-class>org.keycloak.example.ProductSAClientSignedJWTServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServiceAccountExample</servlet-name>
<url-pattern>/app/*</url-pattern>
<servlet-name>ProductSAClientSecretServlet</servlet-name>
<url-pattern>/app-secret/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ProductSAClientSignedJWTServlet</servlet-name>
<url-pattern>/app-jwt/*</url-pattern>
</servlet-mapping>
</web-app>
@@ -1,5 +1,9 @@
<html>
<head>
<meta http-equiv="Refresh" content="0; URL=app">
</head>
<head><title>Service account example</title></head>
<body>
<ul>
<li><a href="app-secret">Client authentication with client secret</a><br /><br /></li>
<li><a href="app-jwt">Client authentication with JWT signed by client private key</a></li>
</ul>
</body>
</html>
+4 -1
View File
@@ -173,7 +173,10 @@
"clientId": "product-sa-client",
"enabled": true,
"secret": "password",
"serviceAccountsEnabled": true
"serviceAccountsEnabled": true,
"attributes": {
"jwt.credential.certificate": "MIICnTCCAYUCBgFPPLDaTzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE3MjI0N1oXDTI1MDgxNzE3MjQyN1owEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIUjjgv+V3s96O+Za9002Lp/trtGuHBeaeVL9dFKMKzO2MPqdRmHB4PqNlDdd28Rwf5Xn6iWdFpyUKOnI/yXDLhdcuFpR0sMNK/C9Lt+hSpPFLuzDqgtPgDotlMxiHIWDOZ7g9/gPYNXbNvjv8nSiyqoguoCQiiafW90bPHsiVLdP7ZIUwCcfi1qQm7FhxRJ1NiW5dvUkuCnnWEf0XR+Wzc5eC9EgB0taLFiPsSEIlWMm5xlahYyXkPdNOqZjiRnrTWm5Y4uk8ZcsD/KbPTf/7t7cQXipVaswgjdYi1kK2/zRwOhg1QwWFX/qmvdd+fLxV0R6VqRDhn7Qep2cxwMxLsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKE6OA46sf20bz8LZPoiNsqRwBUDkaMGXfnob7s/hJZIIwDEx0IAQ3uKsG7q9wb+aA6s+v7S340zb2k3IxuhFaHaZpAd4CyR5cn1FHylbzoZ7rI/3ASqHDqpljdJaFqPH+m7nZWtyDvtZf+gkZ8OjsndwsSBK1d/jMZPp29qYbl1+XfO7RCp/jDqro/R3saYFaIFiEZPeKn1hUJn6BO48vxH1xspSu9FmlvDOEAOz4AuM58z4zRMP49GcFdCWr1wkonJUHaSptJaQwmBwLFUkCbE5I1ixGMb7mjEud6Y5jhfzJiZMo2U8RfcjNbrN0diZl3jB6LQIwESnhYSghaTjNQ=="
}
}
],
"clientScopeMappings": {
@@ -41,7 +41,6 @@ public class AppContextListener implements ServletContextListener {
}
ServletOAuthClientBuilder.build(is, oauthClient);
logger.info("OAuth client configured and started");
oauthClient.start();
}
@Override
@@ -27,8 +27,6 @@ public class Bootstrap implements ServletContextListener {
ServletContext context = sce.getServletContext();
configureClient(context);
client.start();
context.setAttribute(ServletOAuthClient.class.getName(), client);
}