Merge pull request #420 from patriot1burke/master
admin rest example, default origins, effect roles
This commit is contained in:
commit
9c0fa93510
40 changed files with 686 additions and 153 deletions
|
@ -9,11 +9,15 @@ import java.security.Principal;
|
|||
*/
|
||||
public class KeycloakPrincipal implements Principal, Serializable {
|
||||
protected final String name;
|
||||
protected final String surrogate;
|
||||
protected final KeycloakSecurityContext context;
|
||||
|
||||
public KeycloakPrincipal(String name, String surrogate) {
|
||||
public KeycloakPrincipal(String name, KeycloakSecurityContext context) {
|
||||
this.name = name;
|
||||
this.surrogate = surrogate;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public KeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,10 +25,6 @@ public class KeycloakPrincipal implements Principal, Serializable {
|
|||
return name;
|
||||
}
|
||||
|
||||
public String getSurrogate() {
|
||||
return surrogate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -33,16 +33,13 @@ public class KeycloakPrincipal implements Principal, Serializable {
|
|||
KeycloakPrincipal that = (KeycloakPrincipal) o;
|
||||
|
||||
if (!name.equals(that.name)) return false;
|
||||
if (surrogate != null ? !surrogate.equals(that.surrogate) : that.surrogate != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + (surrogate != null ? surrogate.hashCode() : 0);
|
||||
return result;
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,7 @@ public interface ServiceUrlConstants {
|
|||
public static final String TOKEN_SERVICE_ACCESS_CODE_PATH = "/realms/{realm-name}/tokens/access/codes";
|
||||
public static final String TOKEN_SERVICE_REFRESH_PATH = "/realms/{realm-name}/tokens/refresh";
|
||||
public static final String TOKEN_SERVICE_LOGOUT_PATH = "/realms/{realm-name}/tokens/logout";
|
||||
public static final String TOKEN_SERVICE_DIRECT_GRANT_PATH = "/realms/{realm-name}/tokens/grants/access";
|
||||
public static final String ACCOUNT_SERVICE_PATH = "/realms/{realm-name}/account";
|
||||
public static final String REALM_INFO_PATH = "/realms/{realm-name}";
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ public class AccessTokenResponse {
|
|||
@JsonProperty("not-before-policy")
|
||||
protected int notBeforePolicy;
|
||||
|
||||
@JsonProperty("session-state")
|
||||
protected String sessionState;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
@ -74,4 +77,12 @@ public class AccessTokenResponse {
|
|||
public void setNotBeforePolicy(int notBeforePolicy) {
|
||||
this.notBeforePolicy = notBeforePolicy;
|
||||
}
|
||||
|
||||
public String getSessionState() {
|
||||
return sessionState;
|
||||
}
|
||||
|
||||
public void setSessionState(String sessionState) {
|
||||
this.sessionState = sessionState;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ public class OAuthClientRepresentation {
|
|||
protected ClaimRepresentation claims;
|
||||
protected Integer notBefore;
|
||||
protected Boolean publicClient;
|
||||
protected Boolean directGrantsOnly;
|
||||
|
||||
|
||||
public String getId() {
|
||||
|
@ -98,4 +99,12 @@ public class OAuthClientRepresentation {
|
|||
public void setPublicClient(Boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
public Boolean isDirectGrantsOnly() {
|
||||
return directGrantsOnly;
|
||||
}
|
||||
|
||||
public void setDirectGrantsOnly(Boolean directGrantsOnly) {
|
||||
this.directGrantsOnly = directGrantsOnly;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@ var logout = function(){
|
|||
|
||||
|
||||
angular.element(document).ready(function ($http) {
|
||||
console.log("*** here");
|
||||
var keycloakAuth = new Keycloak('keycloak.json');
|
||||
auth.loggedIn = false;
|
||||
|
||||
keycloakAuth.init('login-required').success(function () {
|
||||
keycloakAuth.init({ onLoad: 'login-required' }).success(function () {
|
||||
console.log('here login');
|
||||
auth.loggedIn = true;
|
||||
auth.authz = keycloakAuth;
|
||||
auth.logoutUrl = keycloakAuth.authServerUrl + "/realms/" + keycloakAuth.realm + "/tokens/logout?redirect_uri=http://localhost:8080/angular-product/index.html";
|
||||
|
@ -38,20 +40,20 @@ module.controller('GlobalCtrl', function($scope, $http) {
|
|||
|
||||
};
|
||||
$scope.loadRoles = function() {
|
||||
$http.query("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles").success(function(data) {
|
||||
$http.get("http://localhost-auth:8080/auth/admin/realms/" + auth.authz.realm + "/roles").success(function(data) {
|
||||
$scope.roles = angular.fromJson(data);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
$scope.addRole = function() {
|
||||
$http.post("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles", {name: 'stuff'}).success(function() {
|
||||
$http.post("http://localhost-auth:8080/auth/admin/realms/" + auth.authz.realm + "/roles", {name: 'stuff'}).success(function() {
|
||||
$scope.loadRoles();
|
||||
});
|
||||
|
||||
};
|
||||
$scope.deleteRole = function() {
|
||||
$http.delete("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles/stuff").success(function() {
|
||||
$http.delete("http://localhost-auth:8080/auth/admin/realms/" + auth.authz.realm + "/roles/stuff").success(function() {
|
||||
$scope.loadRoles();
|
||||
});
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ The following examples requires Wildfly 8.0.0, JBoss EAP 6.x, or JBoss AS 7.1.1.
|
|||
* Transferring identity and role mappings via a special bearer token (Skeleton Key Token).
|
||||
* Bearer token authentication and authorization of JAX-RS services
|
||||
* Obtaining bearer tokens via the OAuth2 protocol
|
||||
* Interact with the Keycloak Admin REST Api
|
||||
|
||||
There are multiple WAR projects. These will all run on the same WildFly instance, but pretend each one is running on a different
|
||||
machine on the network or Internet.
|
||||
|
@ -13,6 +14,7 @@ machine on the network or Internet.
|
|||
* **customer-app-js** A pure HTML/Javascript application that does remote login using OAuth2 browser redirects with the auth server
|
||||
* **customer-app-cli** A pure CLI application that does remote login using OAuth2 browser redirects with the auth server
|
||||
* **product-app** A WAR application that does remote login using OAuth2 browser redirects with the auth server
|
||||
* **admin-access-app** A WAR application that does remote REST login to admin console to obtain a list of realm roles from Admin REST API
|
||||
* **database-service** JAX-RS services authenticated by bearer tokens only. The customer and product app invoke on it to get data
|
||||
* **third-party** Simple WAR that obtain a bearer token using OAuth2 using browser redirects to the auth-server.
|
||||
* **third-party-cdi** Simple CDI/JSF WAR that obtain a bearer token using OAuth2 using browser redirects to the auth-server.
|
||||
|
@ -184,6 +186,16 @@ The CLI example has two alternative methods for login. When a browser is availab
|
|||
temporary web server on a free port. If a browser is not available the URL to login is displayed on the CLI. The user can copy this URL to another computer that has a browser available. The code
|
||||
is displayed to the user after login and the user has to copy this code back to the application.
|
||||
|
||||
Step 8: Admin REST API
|
||||
----------------------------------
|
||||
Keycloak has a Admin REST API. This example shows an application making a remove direct login to Keycloak to obtain a token
|
||||
then using that token to access the Admin REST API.
|
||||
|
||||
[http://localhost:8080/admin-access](http://localhost:8080/admin-access)
|
||||
|
||||
If you are already logged in, you will not be asked for a username and password, but you will be redirected to
|
||||
an oauth grant page. This page asks you if you want to grant certain permissions to the third-part app.
|
||||
|
||||
Admin Console
|
||||
==========================
|
||||
|
||||
|
|
76
examples/demo-template/admin-access-app/pom.xml
Executable file
76
examples/demo-template/admin-access-app/pom.xml
Executable file
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-1-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.keycloak.example.demo</groupId>
|
||||
<artifactId>admin-access-example</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Admin Access Example</name>
|
||||
<description/>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss</id>
|
||||
<name>jboss repo</name>
|
||||
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${keycloak.apache.httpcomponents.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>admin-access</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jboss.as.plugins</groupId>
|
||||
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||
<version>7.4.Final</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,151 @@
|
|||
package org.keycloak.example;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.ServiceUrlConstants;
|
||||
import org.keycloak.adapters.HttpClientBuilder;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.util.BasicAuthHelper;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.KeycloakUriBuilder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AdminClient {
|
||||
|
||||
static class TypedList extends ArrayList<RoleRepresentation> {
|
||||
}
|
||||
|
||||
public static class Failure extends Exception {
|
||||
private int status;
|
||||
|
||||
public Failure(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public static AccessTokenResponse getToken() throws IOException {
|
||||
|
||||
HttpClient client = new HttpClientBuilder()
|
||||
.disableTrustManager().build();
|
||||
|
||||
|
||||
try {
|
||||
HttpPost post = new HttpPost(KeycloakUriBuilder.fromUri("http://localhost:8080/auth")
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_DIRECT_GRANT_PATH).build("demo"));
|
||||
List <NameValuePair> formparams = new ArrayList <NameValuePair>();
|
||||
formparams.add(new BasicNameValuePair("username", "admin"));
|
||||
formparams.add(new BasicNameValuePair("password", "password"));
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "admin-client"));
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
post.setEntity(form);
|
||||
|
||||
HttpResponse response = client.execute(post);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (status != 200) {
|
||||
throw new IOException("Bad status: " + status);
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new IOException("No Entity");
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
try {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
int c;
|
||||
while ((c = is.read()) != -1) {
|
||||
os.write(c);
|
||||
}
|
||||
byte[] bytes = os.toByteArray();
|
||||
String json = new String(bytes);
|
||||
try {
|
||||
return JsonSerialization.readValue(json, AccessTokenResponse.class);
|
||||
} catch (IOException e) {
|
||||
throw new IOException(json, e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static void logout(AccessTokenResponse res) throws IOException {
|
||||
|
||||
HttpClient client = new HttpClientBuilder()
|
||||
.disableTrustManager().build();
|
||||
|
||||
|
||||
try {
|
||||
HttpGet get = new HttpGet(KeycloakUriBuilder.fromUri("http://localhost:8080/auth")
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH)
|
||||
.queryParam("session-state", res.getSessionState())
|
||||
.build("demo"));
|
||||
HttpResponse response = client.execute(get);
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<RoleRepresentation> getRealmRoles(AccessTokenResponse res) throws Failure {
|
||||
|
||||
HttpClient client = new HttpClientBuilder()
|
||||
.disableTrustManager().build();
|
||||
try {
|
||||
HttpGet get = new HttpGet("http://localhost:8080/auth/admin/realms/demo/roles");
|
||||
get.addHeader("Authorization", "Bearer " + res.getToken());
|
||||
try {
|
||||
HttpResponse response = client.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new Failure(response.getStatusLine().getStatusCode());
|
||||
}
|
||||
HttpEntity entity = response.getEntity();
|
||||
InputStream is = entity.getContent();
|
||||
try {
|
||||
return JsonSerialization.readValue(is, TypedList.class);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<dependencies>
|
||||
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
|
||||
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
|
||||
<module name="org.apache.httpcomponents"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
9
examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml
Executable file
9
examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml
Executable file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>admin-access</module-name>
|
||||
|
||||
</web-app>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>admin-access</module-name>
|
||||
|
||||
</web-app>
|
30
examples/demo-template/admin-access-app/src/main/webapp/admin/admin.jsp
Executable file
30
examples/demo-template/admin-access-app/src/main/webapp/admin/admin.jsp
Executable file
|
@ -0,0 +1,30 @@
|
|||
<%@ page import="org.keycloak.representations.idm.RoleRepresentation" %>
|
||||
<%@ page import="org.keycloak.example.AdminClient" %>
|
||||
<%@ page import="org.keycloak.representations.AccessTokenResponse" %>
|
||||
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
|
||||
pageEncoding="ISO-8859-1" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Admin Interface</title>
|
||||
</head>
|
||||
<body bgcolor="#E3F6CE">
|
||||
<h2>List of Realm Roles from Admin REST API Call</h2>
|
||||
<%
|
||||
java.util.List<RoleRepresentation> list = null;
|
||||
try {
|
||||
AccessTokenResponse res = AdminClient.getToken();
|
||||
list = AdminClient.getRealmRoles(res);
|
||||
AdminClient.logout(res);
|
||||
} catch (AdminClient.Failure failure) {
|
||||
out.println("There was a failure processing request. You either didn't configure Keycloak properly");
|
||||
out.println("Status from database service invocation was: " + failure.getStatus());
|
||||
return;
|
||||
}
|
||||
for (RoleRepresentation role : list) {
|
||||
out.print("<p>");
|
||||
out.print(role.getName());
|
||||
out.println("</p>");
|
||||
|
||||
}
|
||||
%></body>
|
||||
</html>
|
|
@ -0,0 +1,67 @@
|
|||
package org.keycloak.example;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.HttpClientBuilder;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AdminClient {
|
||||
|
||||
static class TypedList extends ArrayList<RoleRepresentation> {
|
||||
}
|
||||
|
||||
public static class Failure extends Exception {
|
||||
private int status;
|
||||
|
||||
public Failure(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<RoleRepresentation> getRealmRoles(HttpServletRequest req) throws Failure {
|
||||
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
||||
|
||||
HttpClient client = new HttpClientBuilder()
|
||||
.disableTrustManager().build();
|
||||
try {
|
||||
HttpGet get = new HttpGet("http://localhost:8080/auth/admin/realms/demo/roles");
|
||||
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
||||
try {
|
||||
HttpResponse response = client.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new Failure(response.getStatusLine().getStatusCode());
|
||||
}
|
||||
HttpEntity entity = response.getEntity();
|
||||
InputStream is = entity.getContent();
|
||||
try {
|
||||
return JsonSerialization.readValue(is, TypedList.class);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
<%@ page import="org.keycloak.representations.idm.RoleRepresentation" %>
|
||||
<%@ page import="org.keycloak.example.AdminClient" %>
|
||||
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
|
||||
pageEncoding="ISO-8859-1" %>
|
||||
<html>
|
||||
|
@ -8,5 +10,24 @@
|
|||
<h1>Customer Admin Interface</h1>
|
||||
User <b><%=request.getUserPrincipal().getName()%>
|
||||
</b> made this request.
|
||||
</body>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<h2>Admin REST To Get Role List of Realm</h2>
|
||||
<%
|
||||
java.util.List<RoleRepresentation> list = null;
|
||||
try {
|
||||
list = AdminClient.getRealmRoles(request);
|
||||
} catch (AdminClient.Failure failure) {
|
||||
out.println("There was a failure processing request. You either didn't configure Keycloak properly");
|
||||
out.println("Status from database service invocation was: " + failure.getStatus());
|
||||
return;
|
||||
}
|
||||
for (RoleRepresentation role : list) {
|
||||
out.print("<p>");
|
||||
out.print(role.getName());
|
||||
out.println("</p>");
|
||||
|
||||
}
|
||||
%></body>
|
||||
</html>
|
|
@ -38,6 +38,7 @@
|
|||
<module>customer-app-cli</module>
|
||||
<module>customer-app-js</module>
|
||||
<module>product-app</module>
|
||||
<module>admin-access-app</module>
|
||||
<module>angular-product-app</module>
|
||||
<module>database-service</module>
|
||||
<module>third-party</module>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"accessTokenLifespan": 3000,
|
||||
"accessCodeLifespan": 10,
|
||||
"accessCodeLifespanUserAction": 6000,
|
||||
"passwordCredentialGrantAllowed": true,
|
||||
"sslNotRequired": true,
|
||||
"registrationAllowed": false,
|
||||
"social": false,
|
||||
|
@ -22,6 +23,17 @@
|
|||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"username" : "admin",
|
||||
"enabled": true,
|
||||
"email" : "admin@admin.com",
|
||||
"firstName": "Admin",
|
||||
"lastName": "Burke",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"roles" : {
|
||||
|
@ -40,6 +52,10 @@
|
|||
{
|
||||
"username": "bburke@redhat.com",
|
||||
"roles": ["user"]
|
||||
},
|
||||
{
|
||||
"username": "admin",
|
||||
"roles": ["user","admin"]
|
||||
}
|
||||
],
|
||||
"scopeMappings": [
|
||||
|
@ -123,6 +139,13 @@
|
|||
"http://localhost:8080/oauth-client-cdi/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "admin-client",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"directGrantsOnly": true
|
||||
|
||||
}
|
||||
],
|
||||
"applicationRoleMappings": {
|
||||
|
@ -131,7 +154,22 @@
|
|||
"username": "bburke@redhat.com",
|
||||
"roles": ["manage-account"]
|
||||
}
|
||||
],
|
||||
"realm-management": [
|
||||
{
|
||||
"username": "admin",
|
||||
"roles": ["realm-admin"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"applicationScopeMappings": {
|
||||
"realm-management": [
|
||||
{
|
||||
"client": "admin-client",
|
||||
"roles": ["realm-admin"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -489,9 +489,6 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
applications : function(ApplicationListLoader) {
|
||||
return ApplicationListLoader();
|
||||
},
|
||||
roles : function(RoleListLoader) {
|
||||
return RoleListLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ApplicationScopeMappingCtrl'
|
||||
|
@ -603,9 +600,6 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
applications : function(ApplicationListLoader) {
|
||||
return ApplicationListLoader();
|
||||
},
|
||||
roles : function(RoleListLoader) {
|
||||
return RoleListLoader();
|
||||
}
|
||||
},
|
||||
controller : 'OAuthClientScopeMappingCtrl'
|
||||
|
|
|
@ -198,7 +198,7 @@ module.controller('ApplicationInstallationCtrl', function($scope, realm, applica
|
|||
module.controller('ApplicationDetailCtrl', function($scope, realm, application, Application, $location, Dialog, Notifications) {
|
||||
console.log('ApplicationDetailCtrl');
|
||||
|
||||
$scope.clientTypes = [
|
||||
$scope.accessTypes = [
|
||||
"confidential",
|
||||
"public",
|
||||
"bearer-only"
|
||||
|
@ -208,28 +208,27 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
|
|||
$scope.create = !application.name;
|
||||
if (!$scope.create) {
|
||||
$scope.application= angular.copy(application);
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
$scope.accessType = $scope.accessTypes[0];
|
||||
if (application.bearerOnly) {
|
||||
$scope.clientType = $scope.clientTypes[2];
|
||||
$scope.accessType = $scope.accessTypes[2];
|
||||
} else if (application.publicClient) {
|
||||
$scope.clientType = $scope.clientTypes[1];
|
||||
$scope.accessType = $scope.accessTypes[1];
|
||||
}
|
||||
} else {
|
||||
$scope.application = { enabled: true };
|
||||
$scope.application.webOrigins = [];
|
||||
$scope.application.redirectUris = [];
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
$scope.accessType = $scope.accessTypes[0];
|
||||
}
|
||||
|
||||
$scope.changeClientType = function() {
|
||||
console.log('Client Type: ' + $scope.clientType);
|
||||
if ($scope.clientType == "confidential") {
|
||||
$scope.changeAccessType = function() {
|
||||
if ($scope.accessType == "confidential") {
|
||||
$scope.application.bearerOnly = false;
|
||||
$scope.application.publicClient = false;
|
||||
} else if ($scope.clientType == "public") {
|
||||
} else if ($scope.accessType == "public") {
|
||||
$scope.application.bearerOnly = false;
|
||||
$scope.application.publicClient = true;
|
||||
} else if ($scope.clientType == "bearer-only") {
|
||||
} else if ($scope.accessType == "bearer-only") {
|
||||
$scope.application.bearerOnly = true;
|
||||
$scope.application.publicClient = false;
|
||||
}
|
||||
|
@ -267,6 +266,10 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
|
|||
Notifications.error("You must specify at least one redirect uri");
|
||||
} else {
|
||||
if ($scope.create) {
|
||||
if ($scope.application.webOrigins.length == 0) {
|
||||
// let rest api put in default webOrigins
|
||||
$scope.application.webOrigins = null;
|
||||
}
|
||||
Application.save({
|
||||
realm: realm.realm,
|
||||
application: ''
|
||||
|
|
|
@ -77,16 +77,15 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
|
|||
$scope.realm = realm;
|
||||
$scope.create = !oauth.id;
|
||||
|
||||
$scope.clientTypes = [
|
||||
$scope.accessTypes = [
|
||||
"confidential",
|
||||
"public"
|
||||
];
|
||||
|
||||
$scope.changeClientType = function() {
|
||||
console.log('Client Type: ' + $scope.clientType);
|
||||
if ($scope.clientType == "confidential") {
|
||||
$scope.changeAccessType = function() {
|
||||
if ($scope.accessType == "confidential") {
|
||||
$scope.oauth.publicClient = false;
|
||||
} else if ($scope.clientType == "public") {
|
||||
} else if ($scope.accessType == "public") {
|
||||
$scope.oauth.publicClient = true;
|
||||
}
|
||||
};
|
||||
|
@ -94,15 +93,15 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
|
|||
|
||||
if (!$scope.create) {
|
||||
$scope.oauth= angular.copy(oauth);
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
$scope.accessType = $scope.accessTypes[0];
|
||||
if (oauth.publicClient) {
|
||||
$scope.clientType = $scope.clientTypes[1];
|
||||
$scope.accessType = $scope.accessTypes[1];
|
||||
}
|
||||
} else {
|
||||
$scope.oauth = { enabled: true };
|
||||
$scope.oauth.webOrigins = [];
|
||||
$scope.oauth.redirectUris = [];
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
$scope.accessType = $scope.accessTypes[0];
|
||||
}
|
||||
|
||||
$scope.$watch(function() {
|
||||
|
@ -133,7 +132,7 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
|
|||
}
|
||||
|
||||
$scope.save = function() {
|
||||
if (!$scope.oauth.redirectUris || $scope.oauth.redirectUris.length == 0) {
|
||||
if (!$scope.oauth.directGrantsOnly && (!$scope.oauth.redirectUris || $scope.oauth.redirectUris.length == 0)) {
|
||||
Notifications.error("You must specify at least one redirect uri");
|
||||
} else {
|
||||
if ($scope.create) {
|
||||
|
@ -183,129 +182,90 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
|
|||
|
||||
});
|
||||
|
||||
module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm, oauth, roles, applications, OAuthClientRealmScopeMapping, OAuthClientApplicationScopeMapping, ApplicationRole) {
|
||||
module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm, oauth, applications,
|
||||
OAuthClientRealmScopeMapping, OAuthClientApplicationScopeMapping, ApplicationRole,
|
||||
OAuthClientAvailableRealmScopeMapping, OAuthClientAvailableApplicationScopeMapping,
|
||||
OAuthClientCompositeRealmScopeMapping, OAuthClientCompositeApplicationScopeMapping) {
|
||||
$scope.realm = realm;
|
||||
$scope.oauth = oauth;
|
||||
$scope.realmRoles = angular.copy(roles);
|
||||
$scope.selectedRealmRoles = [];
|
||||
$scope.selectedRealmMappings = [];
|
||||
$scope.realmMappings = [];
|
||||
$scope.applications = applications;
|
||||
$scope.applicationRoles = [];
|
||||
$scope.applicationComposite = [];
|
||||
$scope.selectedApplicationRoles = [];
|
||||
$scope.selectedApplicationMappings = [];
|
||||
$scope.applicationMappings = [];
|
||||
$scope.dummymodel = [];
|
||||
|
||||
function updateRealmRoles() {
|
||||
$scope.realmRoles = OAuthClientAvailableRealmScopeMapping.query({realm : realm.realm, oauth : oauth.id});
|
||||
$scope.realmMappings = OAuthClientRealmScopeMapping.query({realm : realm.realm, oauth : oauth.id});
|
||||
$scope.realmComposite = OAuthClientCompositeRealmScopeMapping.query({realm : realm.realm, oauth : oauth.id});
|
||||
}
|
||||
|
||||
|
||||
$scope.realmMappings = OAuthClientRealmScopeMapping.query({realm : realm.realm, oauth : oauth.id}, function(){
|
||||
for (var i = 0; i < $scope.realmMappings.length; i++) {
|
||||
var role = $scope.realmMappings[i];
|
||||
for (var j = 0; j < $scope.realmRoles.length; j++) {
|
||||
var realmRole = $scope.realmRoles[j];
|
||||
if (realmRole.id == role.id) {
|
||||
var idx = $scope.realmRoles.indexOf(realmRole);
|
||||
if (idx != -1) {
|
||||
$scope.realmRoles.splice(idx, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateAppRoles() {
|
||||
if ($scope.targetApp) {
|
||||
console.debug($scope.targetApp.name);
|
||||
$scope.applicationRoles = OAuthClientAvailableApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.id, targetApp : $scope.targetApp.name});
|
||||
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.id, targetApp : $scope.targetApp.name});
|
||||
$scope.applicationComposite = OAuthClientCompositeApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.id, targetApp : $scope.targetApp.name});
|
||||
} else {
|
||||
$scope.applicationRoles = null;
|
||||
$scope.applicationMappings = null;
|
||||
$scope.applicationComposite = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.addRealmRole = function() {
|
||||
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
|
||||
$scope.selectedRealmRoles).success(function() {
|
||||
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
|
||||
var role = $scope.selectedRealmRoles[i];
|
||||
var idx = $scope.realmRoles.indexOf($scope.selectedRealmRoles[i]);
|
||||
if (idx != -1) {
|
||||
$scope.realmRoles.splice(idx, 1);
|
||||
$scope.realmMappings.push(role);
|
||||
}
|
||||
}
|
||||
$scope.selectRealmRoles = [];
|
||||
});
|
||||
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm', $scope.selectedRealmRoles)
|
||||
.success(updateRealmRoles);
|
||||
};
|
||||
|
||||
$scope.deleteRealmRole = function() {
|
||||
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
|
||||
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
|
||||
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
|
||||
var role = $scope.selectedRealmMappings[i];
|
||||
var idx = $scope.realmMappings.indexOf($scope.selectedRealmMappings[i]);
|
||||
if (idx != -1) {
|
||||
$scope.realmMappings.splice(idx, 1);
|
||||
$scope.realmRoles.push(role);
|
||||
}
|
||||
}
|
||||
$scope.selectedRealmMappings = [];
|
||||
});
|
||||
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}})
|
||||
.success(updateRealmRoles);
|
||||
};
|
||||
|
||||
$scope.addApplicationRole = function() {
|
||||
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
|
||||
$scope.selectedApplicationRoles).success(function() {
|
||||
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
|
||||
var role = $scope.selectedApplicationRoles[i];
|
||||
var idx = $scope.applicationRoles.indexOf($scope.selectedApplicationRoles[i]);
|
||||
if (idx != -1) {
|
||||
$scope.applicationRoles.splice(idx, 1);
|
||||
$scope.applicationMappings.push(role);
|
||||
}
|
||||
}
|
||||
$scope.selectedApplicationRoles = [];
|
||||
});
|
||||
$scope.selectedApplicationRoles).success(updateAppRoles);
|
||||
};
|
||||
|
||||
$scope.deleteApplicationRole = function() {
|
||||
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
|
||||
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
|
||||
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
|
||||
var role = $scope.selectedApplicationMappings[i];
|
||||
var idx = $scope.applicationMappings.indexOf($scope.selectedApplicationMappings[i]);
|
||||
if (idx != -1) {
|
||||
$scope.applicationMappings.splice(idx, 1);
|
||||
$scope.applicationRoles.push(role);
|
||||
}
|
||||
}
|
||||
$scope.selectedApplicationMappings = [];
|
||||
});
|
||||
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(updateAppRoles);
|
||||
};
|
||||
|
||||
|
||||
$scope.changeApplication = function() {
|
||||
if ($scope.targetApp) {
|
||||
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.targetApp.name}, function() {
|
||||
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.id, targetApp : $scope.targetApp.name}, function(){
|
||||
for (var i = 0; i < $scope.applicationMappings.length; i++) {
|
||||
var role = $scope.applicationMappings[i];
|
||||
for (var j = 0; j < $scope.applicationRoles.length; j++) {
|
||||
var realmRole = $scope.applicationRoles[j];
|
||||
if (realmRole.id == role.id) {
|
||||
var idx = $scope.applicationRoles.indexOf(realmRole);
|
||||
if (idx != -1) {
|
||||
$scope.applicationRoles.splice(idx, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$scope.targetApp = null;
|
||||
}
|
||||
updateAppRoles();
|
||||
};
|
||||
|
||||
$scope.addRealmRole = function() {
|
||||
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
|
||||
$scope.selectedRealmRoles).success(updateRealmRoles);
|
||||
};
|
||||
|
||||
$scope.deleteRealmRole = function() {
|
||||
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
|
||||
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(updateRealmRoles);
|
||||
};
|
||||
|
||||
$scope.addApplicationRole = function() {
|
||||
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
|
||||
$scope.selectedApplicationRoles).success(updateAppRoles);
|
||||
};
|
||||
|
||||
$scope.deleteApplicationRole = function() {
|
||||
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
|
||||
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(updateAppRoles);
|
||||
};
|
||||
|
||||
updateRealmRoles();
|
||||
});
|
||||
|
||||
|
||||
module.controller('OAuthClientInstallationCtrl', function($scope, realm, installation, oauth, OAuthClientInstallation, $routeParams) {
|
||||
$scope.realm = realm;
|
||||
$scope.oauth = oauth;
|
||||
|
|
|
@ -764,6 +764,20 @@ module.factory('OAuthClientRealmScopeMapping', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientCompositeRealmScopeMapping', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm/composite', {
|
||||
realm : '@realm',
|
||||
oauth : '@oauth'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientAvailableRealmScopeMapping', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm/available', {
|
||||
realm : '@realm',
|
||||
oauth : '@oauth'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientApplicationScopeMapping', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
|
||||
realm : '@realm',
|
||||
|
@ -772,6 +786,24 @@ module.factory('OAuthClientApplicationScopeMapping', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientCompositeApplicationScopeMapping', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/composite', {
|
||||
realm : '@realm',
|
||||
oauth : '@oauth',
|
||||
targetApp : '@targetApp'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientAvailableApplicationScopeMapping', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/available', {
|
||||
realm : '@realm',
|
||||
oauth : '@oauth',
|
||||
targetApp : '@targetApp'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.factory('OAuthClientInstallation', function($resource) {
|
||||
var url = authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation';
|
||||
var resource = $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation', {
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="clientType">Client Type</label>
|
||||
<label class="col-sm-2 control-label" for="accessType">Access Type</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="clientType"
|
||||
ng-change="changeClientType()"
|
||||
ng-model="clientType"
|
||||
ng-options="cType for cType in clientTypes">
|
||||
<select id="accessType"
|
||||
ng-change="changeAccessType()"
|
||||
ng-model="accessType"
|
||||
ng-options="aType for aType in accessTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -49,9 +49,9 @@
|
|||
ng-model="selectedRealmMappings"
|
||||
ng-options="r.name for r in realmMappings">
|
||||
</select>
|
||||
<div class="middle-buttons">
|
||||
-
|
||||
</div>
|
||||
</div>
|
||||
<div class="middle-buttons">
|
||||
-
|
||||
</div>
|
||||
<div class="select-title">
|
||||
<label class="control-label" for="realm-composite">Effective Roles</label>
|
||||
|
|
|
@ -41,18 +41,24 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="clientType">Client Type</label>
|
||||
<label class="col-sm-2 control-label" for="accessType">Access Type</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="clientType"
|
||||
ng-change="changeClientType()"
|
||||
ng-model="clientType"
|
||||
ng-options="cType for cType in clientTypes">
|
||||
<select id="accessType"
|
||||
ng-change="changeAccessType()"
|
||||
ng-model="accessType"
|
||||
ng-options="aType for aType in accessTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="directGrantsOnly">Direct Grants Only</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="oauth.directGrantsOnly" name="directGrantsOnly" id="directGrantsOnly" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-hide="oauth.directGrantsOnly">
|
||||
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI <span class="required" data-ng-show="create">*</span></label>
|
||||
<div class="col-sm-4 multiple" ng-repeat="redirectUri in oauth.redirectUris">
|
||||
<div class="input-group kc-item-deletable">
|
||||
|
@ -75,7 +81,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" data-ng-hide="create">
|
||||
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
|
||||
<div class="col-sm-4 multiple" ng-repeat="webOrigin in oauth.webOrigins">
|
||||
<div class="input-group kc-item-deletable">
|
||||
|
|
|
@ -48,6 +48,17 @@
|
|||
ng-options="r.name for r in realmMappings">
|
||||
</select>
|
||||
</div>
|
||||
<div class="middle-buttons">
|
||||
-
|
||||
</div>
|
||||
<div class="select-title">
|
||||
<label class="control-label" for="realm-composite">Effective Roles</label>
|
||||
<select id="realm-composite" class="form-control" multiple size=5
|
||||
ng-disabled="true"
|
||||
ng-model="dummymodel"
|
||||
ng-options="r.name for r in realmComposite">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -92,6 +103,17 @@
|
|||
ng-options="r.name for r in applicationMappings">
|
||||
</select>
|
||||
</div>
|
||||
<div class="middle-buttons">
|
||||
-
|
||||
</div>
|
||||
<div class="select-title">
|
||||
<label class="control-label" for="app-composite">Effective Roles</label>
|
||||
<select id="app-composite" class="form-control" multiple size=5
|
||||
ng-disabled="true"
|
||||
ng-model="dummymodel"
|
||||
ng-options="r.name for r in applicationComposite">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="passwordCredentialGrantAllowed" class="col-sm-2 control-label">Password Credential Grant</label>
|
||||
<label for="passwordCredentialGrantAllowed" class="col-sm-2 control-label">Direct Grant API</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.passwordCredentialGrantAllowedpasswordCredentialGrantAllowed" name="passwordCredentialGrantAllowed" id="passwordCredentialGrantAllowed" onoffswitch />
|
||||
</div>
|
||||
|
|
|
@ -88,8 +88,8 @@ public abstract class RequestAuthenticator {
|
|||
}
|
||||
|
||||
protected void completeAuthentication(OAuthRequestAuthenticator oauth) {
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(oauth.getToken().getSubject(), null);
|
||||
RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken());
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(oauth.getToken().getSubject(), session);
|
||||
completeOAuthAuthentication(principal, session);
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,8 @@ public abstract class RequestAuthenticator {
|
|||
protected abstract boolean isCached();
|
||||
|
||||
protected void completeAuthentication(BearerTokenRequestAuthenticator bearer) {
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(bearer.getToken().getSubject(), bearer.getSurrogate());
|
||||
RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, bearer.getTokenString(), bearer.getToken(), null, null, null);
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(bearer.getToken().getSubject(), session);
|
||||
completeBearerAuthentication(principal, session);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,9 +73,8 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
|
|||
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realmPublicKey, realm);
|
||||
KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null);
|
||||
ResteasyProviderFactory.pushContext(KeycloakSecurityContext.class, skSession);
|
||||
String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
|
||||
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(token.getSubject(), callerPrincipal);
|
||||
final KeycloakPrincipal principal = new KeycloakPrincipal(token.getSubject(), skSession);
|
||||
final boolean isSecure = securityContext.isSecure();
|
||||
final AccessToken.Access access;
|
||||
if (resourceName != null) {
|
||||
|
|
|
@ -54,6 +54,9 @@ public interface ClientModel {
|
|||
boolean isPublicClient();
|
||||
void setPublicClient(boolean flag);
|
||||
|
||||
boolean isDirectGrantsOnly();
|
||||
void setDirectGrantsOnly(boolean flag);
|
||||
|
||||
RealmModel getRealm();
|
||||
|
||||
/**
|
||||
|
|
9
model/api/src/main/java/org/keycloak/models/entities/OAuthClientEntity.java
Normal file → Executable file
9
model/api/src/main/java/org/keycloak/models/entities/OAuthClientEntity.java
Normal file → Executable file
|
@ -4,4 +4,13 @@ package org.keycloak.models.entities;
|
|||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class OAuthClientEntity extends ClientEntity {
|
||||
protected boolean directGrantsOnly;
|
||||
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return directGrantsOnly;
|
||||
}
|
||||
|
||||
public void setDirectGrantsOnly(boolean directGrantsOnly) {
|
||||
this.directGrantsOnly = directGrantsOnly;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,16 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
|
|||
applicationEntity.setBearerOnly(only);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return false; // applications can't be grant only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectGrantsOnly(boolean flag) {
|
||||
// applications can't be grant only
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel getRole(String name) {
|
||||
TypedQuery<ApplicationRoleEntity> query = em.createNamedQuery("getAppRoleByName", ApplicationRoleEntity.class);
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientAdapter implements ClientModel {
|
||||
public abstract class ClientAdapter implements ClientModel {
|
||||
protected ClientEntity entity;
|
||||
protected RealmModel realm;
|
||||
protected EntityManager em;
|
||||
|
|
|
@ -15,8 +15,11 @@ import java.util.Set;
|
|||
*/
|
||||
public class OAuthClientAdapter extends ClientAdapter implements OAuthClientModel {
|
||||
|
||||
protected final OAuthClientEntity oAuthClientEntity;
|
||||
|
||||
public OAuthClientAdapter(RealmModel realm, OAuthClientEntity entity, EntityManager em) {
|
||||
super(realm, entity, em);
|
||||
oAuthClientEntity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,4 +27,14 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
|
|||
entity.setName(id);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return oAuthClientEntity.isDirectGrantsOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectGrantsOnly(boolean flag) {
|
||||
oAuthClientEntity.setDirectGrantsOnly(flag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,4 +15,13 @@ import javax.persistence.NamedQuery;
|
|||
})
|
||||
@Entity
|
||||
public class OAuthClientEntity extends ClientEntity {
|
||||
protected boolean directGrantsOnly;
|
||||
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return directGrantsOnly;
|
||||
}
|
||||
|
||||
public void setDirectGrantsOnly(boolean directGrantsOnly) {
|
||||
this.directGrantsOnly = directGrantsOnly;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,17 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
|
|||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return false; // applications can't be grant only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectGrantsOnly(boolean flag) {
|
||||
// applications can't be grant only
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RoleAdapter getRole(String name) {
|
||||
DBObject query = new QueryBuilder()
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
|
|||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientAdapter<T extends MongoIdentifiableEntity> extends AbstractMongoAdapter<T> implements ClientModel {
|
||||
public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends AbstractMongoAdapter<T> implements ClientModel {
|
||||
|
||||
protected final T clientEntity;
|
||||
private final RealmAdapter realm;
|
||||
|
|
|
@ -19,4 +19,14 @@ public class OAuthClientAdapter extends ClientAdapter<MongoOAuthClientEntity> im
|
|||
getMongoEntity().setName(id);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectGrantsOnly() {
|
||||
return getMongoEntity().isDirectGrantsOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectGrantsOnly(boolean flag) {
|
||||
getMongoEntity().setDirectGrantsOnly(flag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public class OAuthClientManager {
|
|||
if (rep.getName() != null) model.setClientId(rep.getName());
|
||||
if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
|
||||
if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient());
|
||||
if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly());
|
||||
if (rep.getClaims() != null) {
|
||||
ClaimManager.setClaims(model, rep.getClaims());
|
||||
}
|
||||
|
@ -84,6 +85,7 @@ public class OAuthClientManager {
|
|||
rep.setName(model.getClientId());
|
||||
rep.setEnabled(model.isEnabled());
|
||||
rep.setPublicClient(model.isPublicClient());
|
||||
rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
|
||||
Set<String> redirectUris = model.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||
|
|
|
@ -114,10 +114,12 @@ public class RealmManager {
|
|||
RoleModel adminRole;
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||
realm.addScopeMapping(adminConsole, adminRole);
|
||||
} else {
|
||||
// security roles are defined in application for the realm.
|
||||
String realmAdminApplicationName = getRealmAdminApplicationName(realm);
|
||||
ApplicationModel realmAdminApp = realm.getApplicationByName(realmAdminApplicationName);
|
||||
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
|
||||
}
|
||||
realm.addScopeMapping(adminConsole, adminRole);
|
||||
}
|
||||
|
||||
public String getMasterRealmAdminApplicationName(RealmModel realm) {
|
||||
|
|
|
@ -453,6 +453,7 @@ public class TokenManager {
|
|||
String encodedToken = new JWSBuilder().jsonContent(accessToken).rsa256(realm.getPrivateKey());
|
||||
res.setToken(encodedToken);
|
||||
res.setTokenType("bearer");
|
||||
res.setSessionState(accessToken.getSessionState());
|
||||
if (accessToken.getExpiration() != 0) {
|
||||
res.setExpiresIn(accessToken.getExpiration() - Time.currentTime());
|
||||
}
|
||||
|
|
|
@ -754,7 +754,11 @@ public class TokenService {
|
|||
}
|
||||
if ( (client instanceof ApplicationModel) && ((ApplicationModel)client).isBearerOnly()) {
|
||||
audit.error(Errors.NOT_ALLOWED);
|
||||
return oauth.forwardToSecurityFailure("Bearer-only applications are not allowed to initiate login");
|
||||
return oauth.forwardToSecurityFailure("Bearer-only applications are not allowed to initiate browser login");
|
||||
}
|
||||
if (client.isDirectGrantsOnly()) {
|
||||
audit.error(Errors.NOT_ALLOWED);
|
||||
return oauth.forwardToSecurityFailure("direct-grants-only clients are not allowed to initiate browser login");
|
||||
}
|
||||
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
|
||||
if (redirect == null) {
|
||||
|
|
Loading…
Reference in a new issue