Merge pull request #32 from patriot1burke/master

retire Transaction
This commit is contained in:
Bill Burke 2013-09-11 06:46:09 -07:00
commit 67be783503
54 changed files with 1268 additions and 1318 deletions

View file

@ -29,15 +29,10 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -23,9 +23,9 @@
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -24,8 +24,8 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -11,6 +11,8 @@ import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.SaasService; import org.keycloak.services.resources.SaasService;
import org.keycloak.services.resources.SaasService; import org.keycloak.services.resources.SaasService;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Context;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -20,8 +22,8 @@ import java.io.InputStream;
*/ */
public class DemoApplication extends KeycloakApplication { public class DemoApplication extends KeycloakApplication {
public DemoApplication() { public DemoApplication(@Context ServletContext servletContext) {
super(); super(servletContext);
KeycloakSession session = factory.createSession(); KeycloakSession session = factory.createSession();
session.getTransaction().begin(); session.getTransaction().begin();
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);

View file

@ -21,6 +21,16 @@
<async-supported>true</async-supported> <async-supported>true</async-supported>
</servlet> </servlet>
<filter>
<filter-name>Keycloak Session Management</filter-name>
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Keycloak Session Management</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
<servlet-mapping> <servlet-mapping>
<servlet-name>Resteasy</servlet-name> <servlet-name>Resteasy</servlet-name>
<url-pattern>/rest/*</url-pattern> <url-pattern>/rest/*</url-pattern>

View file

@ -55,11 +55,8 @@ module.config([ '$routeProvider', function($routeProvider) {
resolve : { resolve : {
realm : function(RealmLoader) { realm : function(RealmLoader) {
return RealmLoader(); return RealmLoader();
},
users : function(UserListLoader) {
return UserListLoader();
} }
}, },
controller : 'UserListCtrl' controller : 'UserListCtrl'
}) })

View file

@ -181,15 +181,39 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
}); });
module.controller('UserListCtrl', function($scope, realm, users) { module.controller('UserListCtrl', function($scope, realm, User) {
$scope.realm = realm; $scope.realm = realm;
$scope.users = users; $scope.users = [];
$scope.query = "*";
$scope.attribute = {};
var params = {};
$scope.addAttribute = function() {
console.log('queryAttribute');
params[$scope.attribute.name] = $scope.attribute.value;
for (var key in params) {
$scope.query = " " + key + "=" +params[key];
}
};
$scope.executeQuery = function() {
console.log('executeQuery');
var parameters = angular.copy(params);
parameters["realm"] = realm.id;
$scope.users = User.query(parameters);
};
$scope.clearQuery = function() {
params = {};
$scopre.query = "*";
$scope.users = [];
};
}); });
module.controller('UserDetailCtrl', function($scope, realm, user, User, $location, Dialog, Notifications) { module.controller('UserDetailCtrl', function($scope, realm, user, User, $location, Dialog, Notifications) {
$scope.realm = realm; $scope.realm = realm;
$scope.user = angular.copy(user); $scope.user = angular.copy(user);
$scope.create = !user.userId; $scope.create = !user.username;
$scope.changed = $scope.create; $scope.changed = $scope.create;
@ -201,23 +225,28 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
$scope.save = function() { $scope.save = function() {
if ($scope.userForm.$valid) { if ($scope.userForm.$valid) {
if ($scope.create) {
User.save({
realm: realm.id
}, $scope.user, function () {
$scope.changed = false;
user = angular.copy($scope.user);
$location.url("/realms/" + realm.id + "/users/" + $scope.user.username);
Notifications.success("Created user");
});
} else {
User.update({
realm: realm.id,
userId: $scope.user.username
}, $scope.user, function () {
$scope.changed = false;
user = angular.copy($scope.user);
Notifications.success("Saved changes to user");
});
}
User.save({ } else {
realm : realm.id
}, $scope.user, function() {
$scope.changed = false;
user = angular.copy($scope.user);
if ($scope.create) {
$location.url("/realms/" + realm.id + "/users/" + $scope.user.userId);
Notifications.success("Created user");
} else {
Notifications.success("Saved changes to user");
}
});
} else {
$scope.userForm.showErrors = true; $scope.userForm.showErrors = true;
} }
}; };
@ -236,7 +265,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
Dialog.confirmDelete($scope.user.userId, 'user', function() { Dialog.confirmDelete($scope.user.userId, 'user', function() {
$scope.user.$remove({ $scope.user.$remove({
realm : realm.id, realm : realm.id,
userId : $scope.user.userId userId : $scope.user.username
}, function() { }, function() {
$location.url("/realms/" + realm.id + "/users"); $location.url("/realms/" + realm.id + "/users");
Notifications.success("Deleted user"); Notifications.success("Deleted user");

View file

@ -110,11 +110,11 @@ module.factory('RoleMapping', function($resource) {
}); });
module.factory('User', function($resource) { module.factory('User', function($resource) {
return $resource('/keycloak-server/ui/api/realms/:realm/users/:userId', { return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId', {
realm : '@realm', realm : '@realm',
userId : '@userId' userId : '@userId'
}, { }, {
save : { update : {
method : 'PUT' method : 'PUT'
} }
}); });

View file

@ -6,7 +6,7 @@
<li data-ng-class="path[0] == 'create' && path[1] == 'user' && 'active'"><a <li data-ng-class="path[0] == 'create' && path[1] == 'user' && 'active'"><a
href="#/create/user/{{realm.id}}">New User</a></li> href="#/create/user/{{realm.id}}">New User</a></li>
<li data-ng-class="path[0] == 'find' && path[1] == 'user' && 'active'"><a <li data-ng-class="path[0] == 'find' && path[1] == 'user' && 'active'"><a
href="#/find/user/{{realm.id}}">Find User</a></li> href="#/realms/{{realm.id}}/users">Find User</a></li>
</ul> </ul>
</li> </li>
<li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/realms/{{realm.id}}/roles">Roles</a> <li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/realms/{{realm.id}}/roles">Roles</a>

View file

@ -13,13 +13,13 @@
<div data-ng-show="roleForm.showErrors && roleForm.$error.required" class="alert alert-error">Please fill in <div data-ng-show="roleForm.showErrors && roleForm.$error.required" class="alert alert-error">Please fill in
all required fields all required fields
</div> </div>
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p> <p class="subtitle subtitle-right" data-ng-show="create"><span class="required">*</span> Required fields</p>
<form class="form-horizontal" name="roleForm" novalidate> <form class="form-horizontal" name="roleForm" novalidate>
<fieldset> <fieldset>
<legend>Details</legend> <legend>Details</legend>
<div class="control-group"> <div class="control-group">
<label class="control-label" for="name">Role name <span class="required">*</span></label> <label class="control-label" for="name">Role name <span class="required" data-ng-show="create">*</span></label>
<div class="controls"> <div class="controls">
<input type="text" class="input-xlarge" id="name" name="name" data-ng-model="role.name" <input type="text" class="input-xlarge" id="name" name="name" data-ng-model="role.name"

View file

@ -4,8 +4,6 @@
<div id="actions-bg"></div> <div id="actions-bg"></div>
<div id="container-right" class="span9"> <div id="container-right" class="span9">
<a class="btn btn-small pull-right" href="#/create/role/{{realm.id}}">Add Role</a>
<h1> <h1>
<span class="gray">Realm Roles</span> <span class="gray">Realm Roles</span>
</h1> </h1>

View file

@ -7,26 +7,35 @@
<h1 data-ng-show="create"><span class="gray">New User</span></h1> <h1 data-ng-show="create"><span class="gray">New User</span></h1>
<h1 data-ng-hide="create"> <h1 data-ng-hide="create">
<span class="gray">{{user.userId}}</span> configuration <span class="gray">User {{user.username}}</span>
</h1> </h1>
<div data-ng-show="userForm.showErrors && userForm.$error.required" class="alert alert-error">Please fill in <div data-ng-show="userForm.showErrors && userForm.$error.required" class="alert alert-error">Please fill in
all required fields all required fields
</div> </div>
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p> <p class="subtitle subtitle-right" data-ng-show="create"><span class="required">*</span> Required fields</p>
<form class="form-horizontal" name="userForm" novalidate> <form class="form-horizontal" name="userForm" novalidate>
<fieldset> <fieldset>
<legend>Details</legend> <legend>Details</legend>
<div class="control-group"> <div class="control-group">
<label class="control-label" for="name">Username <span class="required">*</span></label> <label class="control-label" for="name">Username <span class="required" data-ng-show="create">*</span></label>
<div class="controls"> <div class="controls">
<input type="text" class="input-xlarge" id="name" name="name" data-ng-model="user.userId" <input type="text" class="input-xlarge" id="name" name="name" data-ng-model="user.username"
autofocus required data-ng-readonly="!create"> autofocus required data-ng-readonly="!create">
</div> </div>
</div> </div>
<div class="control-group">
<label class="control-label">Enabled</label>
<div class="controls">
<input class="input-xlarge" type="checkbox" name="enabled"
data-ng-model="realm.enabled">
</div>
</div>
<div class="control-group"> <div class="control-group">
<label class="control-label" for="email">Email </label> <label class="control-label" for="email">Email </label>
@ -52,15 +61,6 @@
<input type="text" class="input-xlarge" id="lastName" data-ng-model="user.lastName"> <input type="text" class="input-xlarge" id="lastName" data-ng-model="user.lastName">
</div> </div>
</div> </div>
<div class="control-group">
<label class="control-label" for="password">Password <span class="required">*</span></label>
<div class="controls">
<input type="password" class="input-xlarge" id="password" name="password"
data-ng-model="user.password" data-ng-required="create">
</div>
</div>
</fieldset> </fieldset>
<fieldset data-ng-show="user.attributes.length > 0"> <fieldset data-ng-show="user.attributes.length > 0">
@ -94,7 +94,6 @@
</button> </button>
<button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes <button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes
</button> </button>
<a href="#/realms/{{realm.id}}/users" data-ng-hide="changed">View users &#187;</a>
<button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed"> <button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed">
Delete Delete
</button> </button>

View file

@ -3,13 +3,42 @@
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside> <aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
<div id="actions-bg"></div> <div id="actions-bg"></div>
<div id="container-right" class="span9"> <div id="container-right" class="span9">
<a class="btn btn-small pull-right" href="#/create/user/{{realm.id}}">Add User</a> <form class="form-horizontal" name="queryForm" novalidate>
<div class="control-group">
<label class="control-label">Query </label>
<h1> <div class="controls">
<span class="gray">{{realm.name}}</span> users <input type="text" class="input-xlarge" id="query" name="query" data-ng-model="query"
</h1> autofocus required readonly>
<button type="submit" data-ng-click="executeQuery()" class="btn btn-primary">Execute Query
</button>
</div>
</div>
</form>
<form class="form-horizontal" name="queryAttribute" novalidate>
<fieldset>
<div class="control-group">
<label class="control-label">Predefined Attribute</label>
<div class="controls">
<select style="width: auto;" name="name"
data-ng-model="attribute.name">
<option value="loginName">Login name</option>
<option value="lastName">Last name</option>
<option value="firstName">First name</option>
<option value="email">Email</option>
</select>
<input class="input-small" type="text" name="value"
data-ng-model="attribute.value">
<button type="submit" data-ng-click="addAttribute()" class="btn btn-primary">Add Attribute
</button>
</div>
</div>
</fieldset>
</form>
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered">
<thead> <thead>
<tr> <tr>
@ -20,7 +49,7 @@
</tr> </tr>
</thead> </thead>
<tr data-ng-repeat="user in users"> <tr data-ng-repeat="user in users">
<td><a href="#/realms/{{realm.id}}/users/{{user.userId}}">{{user.userId}}</a></td> <td><a href="#/realms/{{realm.id}}/users/{{user.username}}">{{user.username}}</a></td>
<td>{{user.firstName}}</td> <td>{{user.firstName}}</td>
<td>{{user.lastName}}</td> <td>{{user.lastName}}</td>
<td>{{user.email}}</td> <td>{{user.email}}</td>

View file

@ -33,7 +33,6 @@
<dependency> <dependency>
<groupId>org.jboss.spec.javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<version>1.0.0.Final</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

25
pom.xml
View file

@ -9,7 +9,8 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<resteasy.version>3.0.2.Final</resteasy.version> <resteasy.version>3.0.4.Final</resteasy.version>
<undertow.version>1.0.0.Beta12</undertow.version>
<picketlink.version>2.5.0.Beta6</picketlink.version> <picketlink.version>2.5.0.Beta6</picketlink.version>
</properties> </properties>
@ -108,7 +109,21 @@
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId> <artifactId>tjws</artifactId>
<version>${resteasy.version}</version> <version>${resteasy.version}</version>
<scope>provided</scope> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-undertow</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>${undertow.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
@ -131,9 +146,9 @@
<version>1.9.12</version> <version>1.9.12</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<version>2.5</version> <version>1.0.1.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>

View file

@ -79,12 +79,7 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId> <artifactId>jaxrs-api</artifactId>
<scope>provided</scope> <scope>provided</scope>
@ -105,13 +100,18 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>servlet-api</artifactId> <artifactId>resteasy-undertow</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>io.undertow</groupId>
<artifactId>tjws</artifactId> <artifactId>undertow-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -124,6 +124,11 @@
<artifactId>jackson-mapper-asl</artifactId> <artifactId>jackson-mapper-asl</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId> <artifactId>jackson-xc</artifactId>

View file

@ -7,8 +7,6 @@ import org.keycloak.services.models.KeycloakSessionFactory;
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.PreMatching; import javax.ws.rs.container.PreMatching;
import java.io.IOException; import java.io.IOException;

View file

@ -0,0 +1,56 @@
package org.keycloak.services.filters;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.KeycloakTransaction;
import javax.servlet.*;
import java.io.IOException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakSessionServletFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
KeycloakSessionFactory factory = (KeycloakSessionFactory)servletRequest.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
if (factory == null) throw new ServletException("Factory was null");
KeycloakSession session = factory.createSession();
ResteasyProviderFactory.pushContext(KeycloakSession.class, session);
KeycloakTransaction tx = session.getTransaction();
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
tx.begin();
try {
filterChain.doFilter(servletRequest, servletResponse);
if (tx.isActive()) {
if (tx.getRollbackOnly()) tx.rollback();
else tx.commit();
}
} catch (IOException ex) {
if (tx.isActive()) tx.rollback();
throw ex;
} catch (ServletException ex) {
if (tx.isActive()) tx.rollback();
throw ex;
}
catch (RuntimeException ex) {
if (tx.isActive()) tx.rollback();
throw ex;
} finally {
session.close();
ResteasyProviderFactory.clearContextData();
}
}
@Override
public void destroy() {
}
}

View file

@ -16,11 +16,7 @@ import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.SaasService; import org.keycloak.services.resources.SaasService;
import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.Cookie; import javax.ws.rs.core.*;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;

View file

@ -7,7 +7,10 @@ import org.keycloak.services.models.*;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**

View file

@ -5,8 +5,8 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.TokenIdGenerator; import org.keycloak.TokenIdGenerator;
import org.keycloak.representations.idm.admin.LogoutAction; import org.keycloak.representations.idm.admin.LogoutAction;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ApplicationModel; import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.RealmModel;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;

View file

@ -1,12 +1,7 @@
package org.keycloak.services.managers; package org.keycloak.services.managers;
import org.keycloak.representations.idm.*; import org.keycloak.representations.idm.*;
import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.services.models.*;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -5,8 +5,8 @@ import org.jboss.resteasy.jose.jws.JWSBuilder;
import org.jboss.resteasy.jwt.JsonSerialization; import org.jboss.resteasy.jwt.JsonSerialization;
import org.keycloak.representations.SkeletonKeyScope; import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ApplicationModel; import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel; import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;

View file

@ -0,0 +1,89 @@
package org.keycloak.services.managers;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserManager {
public static UserRepresentation toRepresentation(UserModel user) {
UserRepresentation rep = new UserRepresentation();
rep.setEmail(user.getEmail());
rep.setLastName(user.getLastName());
rep.setFirstName(user.getFirstName());
rep.setEnabled(user.isEnabled());
rep.setUsername(user.getLoginName());
for (Map.Entry<String, String> entry : user.getAttributes().entrySet()) {
rep.attribute(entry.getKey(), entry.getValue());
}
return rep;
}
public UserModel createUser(RealmModel newRealm, UserRepresentation userRep) {
UserModel user = newRealm.addUser(userRep.getUsername());
user.setEnabled(userRep.isEnabled());
user.setEmail(userRep.getEmail());
user.setFirstName(userRep.getFirstName());
user.setLastName(userRep.getLastName());
if (userRep.getAttributes() != null) {
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
user.setAttribute(entry.getKey(), entry.getValue());
}
}
if (userRep.getCredentials() != null) {
for (CredentialRepresentation cred : userRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
newRealm.updateCredential(user, credential);
}
}
return user;
}
/**
* Doesn't allow you to change loginname.
*
* @param user
* @param userRep
*/
public void updateUserAsAdmin(UserModel user, UserRepresentation userRep) {
user.setEnabled(userRep.isEnabled());
user.setEmail(userRep.getEmail());
user.setFirstName(userRep.getFirstName());
user.setLastName(userRep.getLastName());
if (userRep.getAttributes() != null) {
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
user.setAttribute(entry.getKey(), entry.getValue());
}
}
}
/**
* Doesn't allow you to change loginname.
* Doesn't allow you to change enable
*
* @param user
* @param userRep
*/
public void updateUserAsUser(UserModel user, UserRepresentation userRep) {
user.setEmail(userRep.getEmail());
user.setFirstName(userRep.getFirstName());
user.setLastName(userRep.getLastName());
if (userRep.getAttributes() != null) {
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
user.setAttribute(entry.getKey(), entry.getValue());
}
}
}
}

View file

@ -7,6 +7,10 @@ import java.util.Map;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface UserModel { public interface UserModel {
public static final String LAST_NAME = "lastName";
public static final String FIRST_NAME = "firstName";
public static final String EMAIL = "email";
String getLoginName(); String getLoginName();
boolean isEnabled(); boolean isEnabled();

View file

@ -1,13 +1,7 @@
package org.keycloak.services.models.jpa.entities; package org.keycloak.services.models.jpa.entities;
import javax.persistence.CascadeType; import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import java.util.Collection; import java.util.Collection;
/** /**

View file

@ -1,13 +1,6 @@
package org.keycloak.services.models.jpa.entities; package org.keycloak.services.models.jpa.entities;
import javax.persistence.CascadeType; import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import java.util.Collection; import java.util.Collection;
/** /**

View file

@ -4,7 +4,6 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -3,7 +3,6 @@ package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.model.Attribute; import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.sample.User; import org.picketlink.idm.model.sample.User;
import java.util.HashMap; import java.util.HashMap;

View file

@ -1,6 +1,5 @@
package org.keycloak.services.models.picketlink.mappings; package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.model.AbstractPartition; import org.picketlink.idm.model.AbstractPartition;
import org.picketlink.idm.model.annotation.AttributeProperty; import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.sample.User; import org.picketlink.idm.model.sample.User;

View file

@ -1,6 +1,5 @@
package org.keycloak.services.models.picketlink.mappings; package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.model.AbstractPartition; import org.picketlink.idm.model.AbstractPartition;
import org.picketlink.idm.model.annotation.AttributeProperty; import org.picketlink.idm.model.annotation.AttributeProperty;

View file

@ -1,10 +1,8 @@
package org.keycloak.services.models.picketlink.relationships; package org.keycloak.services.models.picketlink.relationships;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.picketlink.idm.model.AbstractAttributedType; import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Attribute; import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship; import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.sample.User; import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter; import org.picketlink.idm.query.AttributeParameter;
import org.picketlink.idm.query.RelationshipQueryParameter; import org.picketlink.idm.query.RelationshipQueryParameter;

View file

@ -21,18 +21,6 @@
*/ */
package org.keycloak.services.resources; package org.keycloak.services.resources;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.Status;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
@ -45,6 +33,13 @@ import org.keycloak.services.resources.flows.FormFlows;
import org.keycloak.services.validation.Validation; import org.keycloak.services.validation.Validation;
import org.picketlink.idm.credential.util.TimeBasedOTP; import org.picketlink.idm.credential.util.TimeBasedOTP;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.Status;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@ -70,184 +65,151 @@ public class AccountService {
@Path("access") @Path("access")
@GET @GET
public Response accessPage() { public Response accessPage() {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); return Flows.forms(realm, request).setUser(user).forwardToAccess();
if (user != null) { } else {
return Flows.forms(realm, request).setUser(user).forwardToAccess(); return Response.status(Status.FORBIDDEN).build();
} else { }
return Response.status(Status.FORBIDDEN).build();
}
}
}.call();
} }
@Path("") @Path("")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) { public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); user.setFirstName(formData.getFirst("firstName"));
if (user != null) { user.setLastName(formData.getFirst("lastName"));
user.setFirstName(formData.getFirst("firstName")); user.setEmail(formData.getFirst("email"));
user.setLastName(formData.getFirst("lastName"));
user.setEmail(formData.getFirst("email"));
return Flows.forms(realm, request).setUser(user).forwardToAccount(); return Flows.forms(realm, request).setUser(user).forwardToAccount();
} else { } else {
return Response.status(Status.FORBIDDEN).build(); return Response.status(Status.FORBIDDEN).build();
} }
}
}.call();
} }
@Path("totp") @Path("totp")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) { public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); FormFlows forms = Flows.forms(realm, request);
if (user != null) {
FormFlows forms = Flows.forms(realm, request);
String totp = formData.getFirst("totp"); String totp = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret"); String totpSecret = formData.getFirst("totpSecret");
String error = null; String error = null;
if (Validation.isEmpty(totp)) { if (Validation.isEmpty(totp)) {
error = Messages.MISSING_TOTP; error = Messages.MISSING_TOTP;
} else if (!new TimeBasedOTP().validate(totp, totpSecret.getBytes())) { } else if (!new TimeBasedOTP().validate(totp, totpSecret.getBytes())) {
error = Messages.INVALID_TOTP; error = Messages.INVALID_TOTP;
}
if (error != null) {
return forms.setError(error).forwardToTotp();
}
UserCredentialModel credentials = new UserCredentialModel();
credentials.setType(CredentialRepresentation.TOTP);
credentials.setValue(formData.getFirst("totpSecret"));
realm.updateCredential(user, credentials);
if (!user.isEnabled() && "REQUIRED".equals(user.getAttribute("KEYCLOAK_TOTP"))) {
user.setEnabled(true);
}
user.setAttribute("KEYCLOAK_TOTP", "ENABLED");
return Flows.forms(realm, request).setUser(user).forwardToTotp();
} else {
return Response.status(Status.FORBIDDEN).build();
}
} }
}.call();
if (error != null) {
return forms.setError(error).forwardToTotp();
}
UserCredentialModel credentials = new UserCredentialModel();
credentials.setType(CredentialRepresentation.TOTP);
credentials.setValue(formData.getFirst("totpSecret"));
realm.updateCredential(user, credentials);
if (!user.isEnabled() && "REQUIRED".equals(user.getAttribute("KEYCLOAK_TOTP"))) {
user.setEnabled(true);
}
user.setAttribute("KEYCLOAK_TOTP", "ENABLED");
return Flows.forms(realm, request).setUser(user).forwardToTotp();
} else {
return Response.status(Status.FORBIDDEN).build();
}
} }
@Path("password") @Path("password")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) { public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); FormFlows forms = Flows.forms(realm, request).setUser(user);
if (user != null) {
FormFlows forms = Flows.forms(realm, request).setUser(user);
String password = formData.getFirst("password"); String password = formData.getFirst("password");
String passwordNew = formData.getFirst("password-new"); String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm"); String passwordConfirm = formData.getFirst("password-confirm");
String error = null; String error = null;
if (Validation.isEmpty(password)) { if (Validation.isEmpty(password)) {
error = Messages.MISSING_PASSWORD; error = Messages.MISSING_PASSWORD;
} else if (Validation.isEmpty(passwordNew)) { } else if (Validation.isEmpty(passwordNew)) {
error = Messages.MISSING_PASSWORD; error = Messages.MISSING_PASSWORD;
} else if (!passwordNew.equals(passwordConfirm)) { } else if (!passwordNew.equals(passwordConfirm)) {
error = Messages.INVALID_PASSWORD_CONFIRM; error = Messages.INVALID_PASSWORD_CONFIRM;
} else if (!realm.validatePassword(user, password)) { } else if (!realm.validatePassword(user, password)) {
error = Messages.INVALID_PASSWORD_EXISTING; error = Messages.INVALID_PASSWORD_EXISTING;
}
if (error != null) {
return forms.setError(error).forwardToPassword();
}
UserCredentialModel credentials = new UserCredentialModel();
credentials.setType(CredentialRepresentation.PASSWORD);
credentials.setValue(passwordNew);
realm.updateCredential(user, credentials);
return Flows.forms(realm, request).setUser(user).forwardToPassword();
} else {
return Response.status(Status.FORBIDDEN).build();
}
} }
}.call();
if (error != null) {
return forms.setError(error).forwardToPassword();
}
UserCredentialModel credentials = new UserCredentialModel();
credentials.setType(CredentialRepresentation.PASSWORD);
credentials.setValue(passwordNew);
realm.updateCredential(user, credentials);
return Flows.forms(realm, request).setUser(user).forwardToPassword();
} else {
return Response.status(Status.FORBIDDEN).build();
}
} }
@Path("") @Path("")
@GET @GET
public Response accountPage() { public Response accountPage() {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); return Flows.forms(realm, request).setUser(user).forwardToAccount();
if (user != null) { } else {
return Flows.forms(realm, request).setUser(user).forwardToAccount(); return Response.status(Status.FORBIDDEN).build();
} else { }
return Response.status(Status.FORBIDDEN).build();
}
}
}.call();
} }
@Path("social") @Path("social")
@GET @GET
public Response socialPage() { public Response socialPage() {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); return Flows.forms(realm, request).setUser(user).forwardToSocial();
if (user != null) { } else {
return Flows.forms(realm, request).setUser(user).forwardToSocial(); return Response.status(Status.FORBIDDEN).build();
} else { }
return Response.status(Status.FORBIDDEN).build();
}
}
}.call();
} }
@Path("totp") @Path("totp")
@GET @GET
public Response totpPage() { public Response totpPage() {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); return Flows.forms(realm, request).setUser(user).forwardToTotp();
if (user != null) { } else {
return Flows.forms(realm, request).setUser(user).forwardToTotp(); return Response.status(Status.FORBIDDEN).build();
} else { }
return Response.status(Status.FORBIDDEN).build();
}
}
}.call();
} }
@Path("password") @Path("password")
@GET @GET
public Response passwordPage() { public Response passwordPage() {
return new Transaction<Response>() { UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
protected Response callImpl() { if (user != null) {
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); return Flows.forms(realm, request).setUser(user).forwardToPassword();
if (user != null) { } else {
return Flows.forms(realm, request).setUser(user).forwardToPassword(); return Response.status(Status.FORBIDDEN).build();
} else { }
return Response.status(Status.FORBIDDEN).build();
}
}
}.call();
} }
} }

View file

@ -1,7 +1,6 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.keycloak.SkeletonKeyContextResolver; import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.services.filters.KeycloakSessionCleanupFilter;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.KeycloakSessionFactory; import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession; import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession;
@ -13,25 +12,15 @@ import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.IdentityConfigurationBuilder; import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.internal.DefaultPartitionManager; import org.picketlink.idm.internal.DefaultPartitionManager;
import org.picketlink.idm.jpa.internal.JPAContextInitializer; import org.picketlink.idm.jpa.internal.JPAContextInitializer;
import org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity; import org.picketlink.idm.jpa.model.sample.simple.*;
import org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence; import javax.persistence.Persistence;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application; import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -45,10 +34,11 @@ public class KeycloakApplication extends Application {
protected KeycloakSessionFactory factory; protected KeycloakSessionFactory factory;
public KeycloakApplication() { public KeycloakApplication(@Context ServletContext context) {
KeycloakSessionFactory f = createSessionFactory(); KeycloakSessionFactory f = createSessionFactory();
this.factory = f; this.factory = f;
classes.add(KeycloakSessionCleanupFilter.class); context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
//classes.add(KeycloakSessionCleanupFilter.class);
TokenManager tokenManager = new TokenManager(); TokenManager tokenManager = new TokenManager();
@ -56,6 +46,7 @@ public class KeycloakApplication extends Application {
singletons.add(new SocialResource(tokenManager, new SocialRequestManager())); singletons.add(new SocialResource(tokenManager, new SocialRequestManager()));
classes.add(SkeletonKeyContextResolver.class); classes.add(SkeletonKeyContextResolver.class);
classes.add(SaasService.class); classes.add(SaasService.class);
} }
protected KeycloakSessionFactory createSessionFactory() { protected KeycloakSessionFactory createSessionFactory() {

View file

@ -3,7 +3,6 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.PublishedRealmRepresentation; import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -41,11 +40,7 @@ public class PublicRealmResource {
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) { public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) {
return new Transaction<PublishedRealmRepresentation>() { return realmRep(realm, uriInfo);
protected PublishedRealmRepresentation callImpl() {
return realmRep(realm, uriInfo);
}
}.call();
} }
@GET @GET
@ -53,26 +48,22 @@ public class PublicRealmResource {
@Path("html") @Path("html")
@Produces("text/html") @Produces("text/html")
public String getRealmHtml(@PathParam("realm") String id) { public String getRealmHtml(@PathParam("realm") String id) {
return new Transaction<String>() { StringBuffer html = new StringBuffer();
protected String callImpl() {
StringBuffer html = new StringBuffer();
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString(); String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString();
String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString(); String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString();
String grantUrl = TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString(); String grantUrl = TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString();
String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString(); String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString();
html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>"); html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
html.append("<p>auth: ").append(authUri).append("</p>"); html.append("<p>auth: ").append(authUri).append("</p>");
html.append("<p>code: ").append(codeUri).append("</p>"); html.append("<p>code: ").append(codeUri).append("</p>");
html.append("<p>grant: ").append(grantUrl).append("</p>"); html.append("<p>grant: ").append(grantUrl).append("</p>");
html.append("<p>identity grant: ").append(idGrantUrl).append("</p>"); html.append("<p>identity grant: ").append(idGrantUrl).append("</p>");
html.append("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>"); html.append("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>");
html.append("</body></html>"); html.append("</body></html>");
return html.toString(); return html.toString();
}
}.call();
} }

View file

@ -1,26 +1,17 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.social.SocialRequestManager;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.container.ResourceContext; import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@ -39,7 +30,10 @@ public class RealmsResource {
protected HttpHeaders headers; protected HttpHeaders headers;
@Context @Context
ResourceContext resourceContext; protected ResourceContext resourceContext;
@Context
protected KeycloakSession session;
protected TokenManager tokenManager; protected TokenManager tokenManager;
@ -53,57 +47,41 @@ public class RealmsResource {
@Path("{realm}/tokens") @Path("{realm}/tokens")
public TokenService getTokenService(final @PathParam("realm") String id) { public TokenService getTokenService(final @PathParam("realm") String id) {
return new Transaction<TokenService>(false) { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.getRealm(id);
protected TokenService callImpl() { if (realm == null) {
RealmManager realmManager = new RealmManager(session); logger.debug("realm not found");
RealmModel realm = realmManager.getRealm(id); throw new NotFoundException();
if (realm == null) { }
logger.debug("realm not found"); TokenService tokenService = new TokenService(realm, tokenManager);
throw new NotFoundException(); resourceContext.initResource(tokenService);
} return tokenService;
TokenService tokenService = new TokenService(realm, tokenManager);
resourceContext.initResource(tokenService);
return tokenService;
}
}.call();
} }
@Path("{realm}/account") @Path("{realm}/account")
public AccountService getAccountService(final @PathParam("realm") String id) { public AccountService getAccountService(final @PathParam("realm") String id) {
return new Transaction<AccountService>(false) { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.getRealm(id);
protected AccountService callImpl() { if (realm == null) {
RealmManager realmManager = new RealmManager(session); logger.debug("realm not found");
RealmModel realm = realmManager.getRealm(id); throw new NotFoundException();
if (realm == null) { }
logger.debug("realm not found"); AccountService accountService = new AccountService(realm);
throw new NotFoundException(); resourceContext.initResource(accountService);
} return accountService;
AccountService accountService = new AccountService(realm);
resourceContext.initResource(accountService);
return accountService;
}
}.call();
} }
@Path("{realm}") @Path("{realm}")
public PublicRealmResource getRealmResource(final @PathParam("realm") String id) { public PublicRealmResource getRealmResource(final @PathParam("realm") String id) {
return new Transaction<PublicRealmResource>(false) { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.getRealm(id);
protected PublicRealmResource callImpl() { if (realm == null) {
RealmManager realmManager = new RealmManager(session); logger.debug("realm not found");
RealmModel realm = realmManager.getRealm(id); throw new NotFoundException();
if (realm == null) { }
logger.debug("realm not found"); PublicRealmResource realmResource = new PublicRealmResource(realm);
throw new NotFoundException(); resourceContext.initResource(realmResource);
} return realmResource;
PublicRealmResource realmResource = new PublicRealmResource(realm);
resourceContext.initResource(realmResource);
return realmResource;
}
}.call();
} }

View file

@ -10,18 +10,14 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.*;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.admin.RealmsAdminResource; import org.keycloak.services.resources.admin.RealmsAdminResource;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.validation.Validation; import org.keycloak.services.validation.Validation;
import javax.ws.rs.*; import javax.ws.rs.*;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.*; import javax.ws.rs.core.*;
import java.net.URI; import java.net.URI;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -44,7 +40,13 @@ public class SaasService {
protected HttpRequest request; protected HttpRequest request;
@Context @Context
HttpResponse response; protected HttpResponse response;
@Context
protected KeycloakSession session;
@Context
protected ResourceContext resourceContext;
protected String adminPath = "/saas/admin/index.html"; protected String adminPath = "/saas/admin/index.html";
protected AuthenticationManager authManager = new AuthenticationManager(); protected AuthenticationManager authManager = new AuthenticationManager();
@ -82,22 +84,17 @@ public class SaasService {
@GET @GET
@NoCache @NoCache
public Response keepalive(final @Context HttpHeaders headers) { public Response keepalive(final @Context HttpHeaders headers) {
logger.info("keepalive"); logger.debug("keepalive");
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
public Response callImpl() { if (realm == null)
RealmManager realmManager = new RealmManager(session); throw new NotFoundException();
RealmModel realm = realmManager.defaultRealm(); UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
if (realm == null) if (user == null) {
throw new NotFoundException(); return Response.status(401).build();
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers); }
if (user == null) { NewCookie refreshCookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
return Response.status(401).build(); return Response.noContent().cookie(refreshCookie).build();
}
NewCookie refreshCookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
return Response.noContent().cookie(refreshCookie).build();
}
}.call();
} }
@Path("whoami") @Path("whoami")
@ -105,20 +102,15 @@ public class SaasService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response whoAmI(final @Context HttpHeaders headers) { public Response whoAmI(final @Context HttpHeaders headers) {
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
public Response callImpl() { if (realm == null)
RealmManager realmManager = new RealmManager(session); throw new NotFoundException();
RealmModel realm = realmManager.defaultRealm(); UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
if (realm == null) if (user == null) {
throw new NotFoundException(); return Response.status(401).build();
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers); }
if (user == null) { return Response.ok(new WhoAmI(user.getLoginName(), user.getFirstName() + " " + user.getLastName())).build();
return Response.status(401).build();
}
return Response.ok(new WhoAmI(user.getLoginName(), user.getFirstName() + " " + user.getLastName())).build();
}
}.call();
} }
@Path("isLoggedIn.js") @Path("isLoggedIn.js")
@ -126,24 +118,19 @@ public class SaasService {
@Produces("application/javascript") @Produces("application/javascript")
@NoCache @NoCache
public String isLoggedIn(final @Context HttpHeaders headers) { public String isLoggedIn(final @Context HttpHeaders headers) {
return new Transaction<String>() { logger.debug("WHOAMI Javascript start.");
@Override RealmManager realmManager = new RealmManager(session);
public String callImpl() { RealmModel realm = realmManager.defaultRealm();
logger.info("WHOAMI Javascript start."); if (realm == null) {
RealmManager realmManager = new RealmManager(session); return "var keycloakCookieLoggedIn = false;";
RealmModel realm = realmManager.defaultRealm();
if (realm == null) {
return "var keycloakCookieLoggedIn = false;";
} }
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers); UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
if (user == null) { if (user == null) {
return "var keycloakCookieLoggedIn = false;"; return "var keycloakCookieLoggedIn = false;";
} }
logger.info("WHOAMI: " + user.getLoginName()); logger.debug("WHOAMI: " + user.getLoginName());
return "var keycloakCookieLoggedIn = true;"; return "var keycloakCookieLoggedIn = true;";
}
}.call();
} }
public static UriBuilder contextRoot(UriInfo uriInfo) { public static UriBuilder contextRoot(UriInfo uriInfo) {
@ -156,86 +143,63 @@ public class SaasService {
@Path("admin/realms") @Path("admin/realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) { public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
return new Transaction<RealmsAdminResource>(false) { RealmManager realmManager = new RealmManager(session);
@Override RealmModel saasRealm = realmManager.defaultRealm();
protected RealmsAdminResource callImpl() { if (saasRealm == null)
RealmManager realmManager = new RealmManager(session); throw new NotFoundException();
RealmModel saasRealm = realmManager.defaultRealm(); UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
if (saasRealm == null) if (admin == null) {
throw new NotFoundException(); throw new NotAuthorizedException("Bearer");
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers); }
if (admin == null) { RoleModel creatorRole = saasRealm.getRole(SaasService.REALM_CREATOR_ROLE);
throw new NotAuthorizedException("Bearer"); if (!saasRealm.hasRole(admin, creatorRole)) {
} logger.warn("not a Realm creator");
RoleModel creatorRole = saasRealm.getRole(SaasService.REALM_CREATOR_ROLE); throw new NotAuthorizedException("Bearer");
if (!saasRealm.hasRole(admin, creatorRole)) { }
logger.warn("not a Realm creator"); RealmsAdminResource adminResource = new RealmsAdminResource(admin);
throw new NotAuthorizedException("Bearer"); resourceContext.initResource(adminResource);
} return adminResource;
return new RealmsAdminResource(admin);
}
}.call();
} }
@Path("login") @Path("login")
@GET @GET
@NoCache @NoCache
public void loginPage() { public void loginPage() {
new Transaction() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
protected void runImpl() { authManager.expireSaasIdentityCookie(uriInfo);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
Flows.forms(realm, request).forwardToLogin(); Flows.forms(realm, request).forwardToLogin();
}
}.run();
} }
@Path("registrations") @Path("registrations")
@GET @GET
@NoCache @NoCache
public void registerPage() { public void registerPage() {
new Transaction() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
protected void runImpl() { authManager.expireSaasIdentityCookie(uriInfo);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
Flows.forms(realm, request).forwardToRegistration(); Flows.forms(realm, request).forwardToRegistration();
}
}.run();
} }
@Path("logout") @Path("logout")
@GET @GET
@NoCache @NoCache
public void logout() { public void logout() {
new Transaction() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
protected void runImpl() { authManager.expireSaasIdentityCookie(uriInfo);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
Flows.forms(realm, request).forwardToLogin(); Flows.forms(realm, request).forwardToLogin();
}
}.run();
} }
@Path("logout-cookie") @Path("logout-cookie")
@GET @GET
@NoCache @NoCache
public void logoutCookie() { public void logoutCookie() {
logger.info("*** logoutCookie"); logger.debug("*** logoutCookie");
new Transaction() { authManager.expireSaasIdentityCookie(uriInfo);
@Override
protected void runImpl() {
authManager.expireSaasIdentityCookie(uriInfo);
}
}.run();
} }
@Path("login") @Path("login")
@ -243,132 +207,117 @@ public class SaasService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processLogin(final MultivaluedMap<String, String> formData) { public Response processLogin(final MultivaluedMap<String, String> formData) {
logger.info("processLogin start"); logger.info("processLogin start");
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.defaultRealm();
protected Response callImpl() { if (realm == null)
RealmManager realmManager = new RealmManager(session); throw new NotFoundException();
RealmModel realm = realmManager.defaultRealm();
if (realm == null)
throw new NotFoundException();
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
throw new NotImplementedYetException(); throw new NotImplementedYetException();
} }
String username = formData.getFirst("username"); String username = formData.getFirst("username");
UserModel user = realm.getUser(username); UserModel user = realm.getUser(username);
if (user == null) { if (user == null) {
logger.info("Not Authenticated! Incorrect user name"); logger.info("Not Authenticated! Incorrect user name");
return Flows.forms(realm, request).setError(Messages.INVALID_USER).setFormData(formData) return Flows.forms(realm, request).setError(Messages.INVALID_USER).setFormData(formData)
.forwardToLogin(); .forwardToLogin();
} }
if (!user.isEnabled()) { if (!user.isEnabled()) {
logger.info("Account is disabled, contact admin."); logger.info("Account is disabled, contact admin.");
return Flows.forms(realm, request).setError(Messages.ACCOUNT_DISABLED) return Flows.forms(realm, request).setError(Messages.ACCOUNT_DISABLED)
.setFormData(formData).forwardToLogin(); .setFormData(formData).forwardToLogin();
} }
boolean authenticated = authManager.authenticateForm(realm, user, formData); boolean authenticated = authManager.authenticateForm(realm, user, formData);
if (!authenticated) { if (!authenticated) {
logger.info("Not Authenticated! Invalid credentials"); logger.info("Not Authenticated! Invalid credentials");
return Flows.forms(realm, request).setError(Messages.INVALID_PASSWORD).setFormData(formData) return Flows.forms(realm, request).setError(Messages.INVALID_PASSWORD).setFormData(formData)
.forwardToLogin(); .forwardToLogin();
} }
NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo); NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build(); return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
}
}.call();
} }
@Path("registrations") @Path("registrations")
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response register(final UserRepresentation newUser) { public Response register(final UserRepresentation newUser) {
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel defaultRealm = realmManager.defaultRealm();
protected Response callImpl() { UserModel user = registerMe(defaultRealm, newUser);
RealmManager realmManager = new RealmManager(session); if (user == null) {
RealmModel defaultRealm = realmManager.defaultRealm(); return Response.status(400).type("text/plain").entity("Already exists").build();
UserModel user = registerMe(defaultRealm, newUser); }
if (user == null) { URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
return Response.status(400).type("text/plain").entity("Already exists").build(); return Response.created(uri).build();
}
URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
return Response.created(uri).build();
}
}.call();
} }
@Path("registrations") @Path("registrations")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processRegister(final MultivaluedMap<String, String> formData) { public Response processRegister(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel defaultRealm = realmManager.defaultRealm();
protected Response callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel defaultRealm = realmManager.defaultRealm();
List<String> requiredCredentialTypes = new LinkedList<String>(); List<String> requiredCredentialTypes = new LinkedList<String>();
for (RequiredCredentialModel m : defaultRealm.getRequiredCredentials()) { for (RequiredCredentialModel m : defaultRealm.getRequiredCredentials()) {
requiredCredentialTypes.add(m.getType()); requiredCredentialTypes.add(m.getType());
} }
String error = Validation.validateRegistrationForm(formData, requiredCredentialTypes); String error = Validation.validateRegistrationForm(formData, requiredCredentialTypes);
if (error != null) { if (error != null) {
return Flows.forms(defaultRealm, request).setError(error).setFormData(formData) return Flows.forms(defaultRealm, request).setError(error).setFormData(formData)
.forwardToRegistration(); .forwardToRegistration();
} }
UserRepresentation newUser = new UserRepresentation(); UserRepresentation newUser = new UserRepresentation();
newUser.setUsername(formData.getFirst("username")); newUser.setUsername(formData.getFirst("username"));
newUser.setEmail(formData.getFirst("email")); newUser.setEmail(formData.getFirst("email"));
String fullname = formData.getFirst("name"); String fullname = formData.getFirst("name");
if (fullname != null) { if (fullname != null) {
StringTokenizer tokenizer = new StringTokenizer(fullname, " "); StringTokenizer tokenizer = new StringTokenizer(fullname, " ");
StringBuffer first = null; StringBuffer first = null;
String last = ""; String last = "";
while (tokenizer.hasMoreTokens()) { while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken(); String token = tokenizer.nextToken();
if (tokenizer.hasMoreTokens()) { if (tokenizer.hasMoreTokens()) {
if (first == null) { if (first == null) {
first = new StringBuffer();
} else {
first.append(" ");
}
first.append(token);
} else {
last = token;
}
}
if (first == null)
first = new StringBuffer(); first = new StringBuffer();
newUser.setFirstName(first.toString()); } else {
newUser.setLastName(last); first.append(" ");
}
first.append(token);
} else {
last = token;
} }
if (requiredCredentialTypes.contains(CredentialRepresentation.PASSWORD)) {
newUser.credential(CredentialRepresentation.PASSWORD, formData.getFirst("password"));
}
if (requiredCredentialTypes.contains(CredentialRepresentation.TOTP)) {
newUser.credential(CredentialRepresentation.TOTP, formData.getFirst("password"));
}
UserModel user = registerMe(defaultRealm, newUser);
if (user == null) {
return Flows.forms(defaultRealm, request).setError(Messages.USERNAME_EXISTS)
.setFormData(formData).forwardToRegistration();
}
NewCookie cookie = authManager.createSaasIdentityCookie(defaultRealm, user, uriInfo);
return Response.status(302).location(contextRoot(uriInfo).path(adminPath).build()).cookie(cookie).build();
} }
}.call(); if (first == null)
first = new StringBuffer();
newUser.setFirstName(first.toString());
newUser.setLastName(last);
}
if (requiredCredentialTypes.contains(CredentialRepresentation.PASSWORD)) {
newUser.credential(CredentialRepresentation.PASSWORD, formData.getFirst("password"));
}
if (requiredCredentialTypes.contains(CredentialRepresentation.TOTP)) {
newUser.credential(CredentialRepresentation.TOTP, formData.getFirst("password"));
}
UserModel user = registerMe(defaultRealm, newUser);
if (user == null) {
return Flows.forms(defaultRealm, request).setError(Messages.USERNAME_EXISTS)
.setFormData(formData).forwardToRegistration();
}
NewCookie cookie = authManager.createSaasIdentityCookie(defaultRealm, user, uriInfo);
return Response.status(302).location(contextRoot(uriInfo).path(adminPath).build()).cookie(cookie).build();
} }
protected UserModel registerMe(RealmModel defaultRealm, UserRepresentation newUser) { protected UserModel registerMe(RealmModel defaultRealm, UserRepresentation newUser) {

View file

@ -56,10 +56,7 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.*;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.SocialLinkModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows; import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.resources.flows.PageFlows; import org.keycloak.services.resources.flows.PageFlows;
@ -98,6 +95,10 @@ public class SocialResource {
@Context @Context
ResourceContext resourceContext; ResourceContext resourceContext;
@Context
protected KeycloakSession session;
private SocialRequestManager socialRequestManager; private SocialRequestManager socialRequestManager;
private TokenManager tokenManager; private TokenManager tokenManager;
@ -112,111 +113,107 @@ public class SocialResource {
@GET @GET
@Path("callback") @Path("callback")
public Response callback() throws URISyntaxException { public Response callback() throws URISyntaxException {
return new Transaction<Response>() { Map<String, String[]> queryParams = getQueryParams();
protected Response callImpl() {
Map<String, String[]> queryParams = getQueryParams();
RequestDetails requestData = getRequestDetails(queryParams); RequestDetails requestData = getRequestDetails(queryParams);
SocialProvider provider = getProvider(requestData.getProviderId()); SocialProvider provider = getProvider(requestData.getProviderId());
String realmId = requestData.getClientAttribute("realmId"); String realmId = requestData.getClientAttribute("realmId");
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealm(realmId); RealmModel realm = realmManager.getRealm(realmId);
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager); OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
return oauth.forwardToSecurityFailure("Realm not enabled."); return oauth.forwardToSecurityFailure("Realm not enabled.");
} }
String clientId = requestData.getClientAttributes().get("clientId"); String clientId = requestData.getClientAttributes().get("clientId");
UserModel client = realm.getUser(clientId); UserModel client = realm.getUser(clientId);
if (client == null) { if (client == null) {
return oauth.forwardToSecurityFailure("Unknown login requester."); return oauth.forwardToSecurityFailure("Unknown login requester.");
} }
if (!client.isEnabled()) { if (!client.isEnabled()) {
return oauth.forwardToSecurityFailure("Login requester not enabled."); return oauth.forwardToSecurityFailure("Login requester not enabled.");
} }
String key = System.getProperty("keycloak.social." + requestData.getProviderId() + ".key"); String key = System.getProperty("keycloak.social." + requestData.getProviderId() + ".key");
String secret = System.getProperty("keycloak.social." + requestData.getProviderId() + ".secret"); String secret = System.getProperty("keycloak.social." + requestData.getProviderId() + ".secret");
String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString(); String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri); SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
AuthCallback callback = new AuthCallback(requestData.getSocialAttributes(), queryParams); AuthCallback callback = new AuthCallback(requestData.getSocialAttributes(), queryParams);
SocialUser socialUser = null; SocialUser socialUser = null;
try { try {
socialUser = provider.processCallback(config, callback); socialUser = provider.processCallback(config, callback);
} catch (SocialProviderException e) { } catch (SocialProviderException e) {
logger.warn("Failed to process social callback", e); logger.warn("Failed to process social callback", e);
return oauth.forwardToSecurityFailure("Failed to process social callback"); return oauth.forwardToSecurityFailure("Failed to process social callback");
} }
SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getUsername()); SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getUsername());
UserModel user = realm.getUserBySocialLink(socialLink); UserModel user = realm.getUserBySocialLink(socialLink);
if (user == null) { if (user == null) {
if (!realm.isRegistrationAllowed()) { if (!realm.isRegistrationAllowed()) {
return oauth.forwardToSecurityFailure("Registration not allowed"); return oauth.forwardToSecurityFailure("Registration not allowed");
}
// Automatically register user into realm with his social username (don't redirect to registration screen)
if (realm.isAutomaticRegistrationAfterSocialLogin()) {
if (realm.getUser(socialUser.getUsername()) != null) {
// TODO: Username is already in realm. Show message and let user to bind accounts after he re-authenticate
throw new IllegalStateException("Username " + socialUser.getUsername() +
" already registered in the realm. TODO: bind accounts...");
// TODO: Maybe we should search also by email and bind accounts if user with this email is
// already registered. But actually Keycloak allows duplicate emails
} else {
user = realm.addUser(socialUser.getUsername());
user.setFirstName(socialUser.getFirstName());
user.setLastName(socialUser.getLastName());
user.setEmail(socialUser.getEmail());
}
realm.addSocialLink(user, socialLink);
for (RoleModel role : realm.getDefaultRoles()) {
realm.grantRole(user, role);
}
} else {
// Redirect user to registration screen with prefilled data from social provider
MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
RequestDetailsBuilder reqDetailsBuilder = RequestDetailsBuilder.createFromRequestDetails(requestData);
reqDetailsBuilder.putSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK, socialLink);
String requestId = UUID.randomUUID().toString();
socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
boolean secureOnly = !realm.isSslNotRequired();
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
logger.info("creating cookie for social registration - name: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE
+ " path: " + cookiePath);
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, requestId,
cookiePath, null, "Added social cookie", NewCookie.DEFAULT_MAX_AGE, secureOnly);
response.addNewCookie(newCookie);
return Flows.forms(realm, request).setFormData(formData).setSocialRegistration(true).forwardToRegistration();
}
}
if (!user.isEnabled()) {
return oauth.forwardToSecurityFailure("Your account is not enabled.");
}
String scope = requestData.getClientAttributes().get("scope");
String state = requestData.getClientAttributes().get("state");
String redirectUri = requestData.getClientAttributes().get("redirectUri");
return oauth.processAccessCode(scope, state, redirectUri, client, user);
} }
}.call();
// Automatically register user into realm with his social username (don't redirect to registration screen)
if (realm.isAutomaticRegistrationAfterSocialLogin()) {
if (realm.getUser(socialUser.getUsername()) != null) {
// TODO: Username is already in realm. Show message and let user to bind accounts after he re-authenticate
throw new IllegalStateException("Username " + socialUser.getUsername() +
" already registered in the realm. TODO: bind accounts...");
// TODO: Maybe we should search also by email and bind accounts if user with this email is
// already registered. But actually Keycloak allows duplicate emails
} else {
user = realm.addUser(socialUser.getUsername());
user.setFirstName(socialUser.getFirstName());
user.setLastName(socialUser.getLastName());
user.setEmail(socialUser.getEmail());
}
realm.addSocialLink(user, socialLink);
for (RoleModel role : realm.getDefaultRoles()) {
realm.grantRole(user, role);
}
} else {
// Redirect user to registration screen with prefilled data from social provider
MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
RequestDetailsBuilder reqDetailsBuilder = RequestDetailsBuilder.createFromRequestDetails(requestData);
reqDetailsBuilder.putSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK, socialLink);
String requestId = UUID.randomUUID().toString();
socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
boolean secureOnly = !realm.isSslNotRequired();
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
logger.info("creating cookie for social registration - name: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE
+ " path: " + cookiePath);
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, requestId,
cookiePath, null, "Added social cookie", NewCookie.DEFAULT_MAX_AGE, secureOnly);
response.addNewCookie(newCookie);
return Flows.forms(realm, request).setFormData(formData).setSocialRegistration(true).forwardToRegistration();
}
}
if (!user.isEnabled()) {
return oauth.forwardToSecurityFailure("Your account is not enabled.");
}
String scope = requestData.getClientAttributes().get("scope");
String state = requestData.getClientAttributes().get("state");
String redirectUri = requestData.getClientAttributes().get("redirectUri");
return oauth.processAccessCode(scope, state, redirectUri, client, user);
} }
@GET @GET
@ -257,63 +254,59 @@ public class SocialResource {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response socialRegistration(@PathParam("realm") final String realmId, public Response socialRegistration(@PathParam("realm") final String realmId,
final MultivaluedMap<String, String> formData) { final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { PageFlows pageFlows = Flows.pages(request);
protected Response callImpl() { Cookie cookie = headers.getCookies().get(SocialConstants.SOCIAL_REGISTRATION_COOKIE);
PageFlows pageFlows = Flows.pages(request); if (cookie == null) {
Cookie cookie = headers.getCookies().get(SocialConstants.SOCIAL_REGISTRATION_COOKIE); return pageFlows.forwardToSecurityFailure("Social registration cookie not found");
if (cookie == null) { }
return pageFlows.forwardToSecurityFailure("Social registration cookie not found");
}
String requestId = cookie.getValue(); String requestId = cookie.getValue();
if (!socialRequestManager.isRequestId(requestId)) { if (!socialRequestManager.isRequestId(requestId)) {
logger.error("Unknown requestId found in cookie. Maybe it's expired. requestId=" + requestId); logger.error("Unknown requestId found in cookie. Maybe it's expired. requestId=" + requestId);
return pageFlows.forwardToSecurityFailure("Unknown requestId found in cookie. Maybe it's expired."); return pageFlows.forwardToSecurityFailure("Unknown requestId found in cookie. Maybe it's expired.");
} }
RequestDetails requestData = socialRequestManager.getData(requestId); RequestDetails requestData = socialRequestManager.getData(requestId);
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealm(realmId); RealmModel realm = realmManager.getRealm(realmId);
if (realm == null || !realm.isEnabled()) { if (realm == null || !realm.isEnabled()) {
return pageFlows.forwardToSecurityFailure("Realm doesn't exists or is not enabled."); return pageFlows.forwardToSecurityFailure("Realm doesn't exists or is not enabled.");
} }
TokenService tokenService = new TokenService(realm, tokenManager); TokenService tokenService = new TokenService(realm, tokenManager);
resourceContext.initResource(tokenService); resourceContext.initResource(tokenService);
String clientId = requestData.getClientAttribute("clientId"); String clientId = requestData.getClientAttribute("clientId");
String scope = requestData.getClientAttribute("scope"); String scope = requestData.getClientAttribute("scope");
String state = requestData.getClientAttribute("state"); String state = requestData.getClientAttribute("state");
String redirectUri = requestData.getClientAttribute("redirectUri"); String redirectUri = requestData.getClientAttribute("redirectUri");
SocialLinkModel socialLink = (SocialLinkModel)requestData.getSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK); SocialLinkModel socialLink = (SocialLinkModel)requestData.getSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK);
Response response1 = tokenService.processRegisterImpl(clientId, scope, state, redirectUri, formData, true); Response response1 = tokenService.processRegisterImpl(clientId, scope, state, redirectUri, formData, true);
// Some error occured during registration // Some error occured during registration
if (response1 != null || request.wasForwarded()) { if (response1 != null || request.wasForwarded()) {
logger.warn("Registration attempt wasn't successful. Request already forwarded or redirected."); logger.warn("Registration attempt wasn't successful. Request already forwarded or redirected.");
return response1; return response1;
} }
String username = formData.getFirst("username"); String username = formData.getFirst("username");
UserModel user = realm.getUser(username); UserModel user = realm.getUser(username);
if (user == null) { if (user == null) {
// Normally shouldn't happen // Normally shouldn't happen
throw new IllegalStateException("User " + username + " not found in the realm"); throw new IllegalStateException("User " + username + " not found in the realm");
} }
realm.addSocialLink(user, socialLink); realm.addSocialLink(user, socialLink);
// Expire cookie and invalidate requestData // Expire cookie and invalidate requestData
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath(); String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, "", cookiePath, null, NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, "", cookiePath, null,
"Expire social cookie", 0, false); "Expire social cookie", 0, false);
logger.info("Expiring social registration cookie: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE + ", path: " + cookiePath); logger.info("Expiring social registration cookie: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE + ", path: " + cookiePath);
response.addNewCookie(newCookie); response.addNewCookie(newCookie);
socialRequestManager.retrieveData(requestId); socialRequestManager.retrieveData(requestId);
return tokenService.processLogin(clientId, scope, state, redirectUri, formData); return tokenService.processLogin(clientId, scope, state, redirectUri, formData);
}
}.call();
} }
private RequestDetails getRequestDetails(Map<String, String[]> queryParams) { private RequestDetails getRequestDetails(Map<String, String[]> queryParams) {

View file

@ -18,11 +18,7 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.*;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows; import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.validation.Validation; import org.keycloak.services.validation.Validation;
@ -75,9 +71,14 @@ public class TokenService {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
@Context @Context
HttpRequest request; protected HttpRequest request;
@Context @Context
HttpResponse response; protected HttpResponse response;
@Context
protected KeycloakSession session;
@Context
protected KeycloakTransaction transaction;
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager(); private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
@ -123,32 +124,28 @@ public class TokenService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response grantIdentityToken(final MultivaluedMap<String, String> form) { public Response grantIdentityToken(final MultivaluedMap<String, String> form) {
return new Transaction<Response>() { String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
protected Response callImpl() { if (username == null) {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); throw new NotAuthorizedException("No user");
if (username == null) { }
throw new NotAuthorizedException("No user"); if (!realm.isEnabled()) {
} throw new NotAuthorizedException("Disabled realm");
if (!realm.isEnabled()) { }
throw new NotAuthorizedException("Disabled realm"); UserModel user = realm.getUser(username);
} if (user == null) {
UserModel user = realm.getUser(username); throw new NotAuthorizedException("No user");
if (user == null) { }
throw new NotAuthorizedException("No user"); if (!user.isEnabled()) {
} throw new NotAuthorizedException("Disabled user.");
if (!user.isEnabled()) { }
throw new NotAuthorizedException("Disabled user."); if (!authManager.authenticateForm(realm, user, form)) {
} throw new NotAuthorizedException("FORM");
if (!authManager.authenticateForm(realm, user, form)) { }
throw new NotAuthorizedException("FORM"); tokenManager = new TokenManager();
} SkeletonKeyToken token = authManager.createIdentityToken(realm, username);
tokenManager = new TokenManager(); String encoded = tokenManager.encodeToken(realm, token);
SkeletonKeyToken token = authManager.createIdentityToken(realm, username); AccessTokenResponse res = accessTokenResponse(token, encoded);
String encoded = tokenManager.encodeToken(realm, token); return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
}
}.call();
} }
@Path("grants/access") @Path("grants/access")
@ -156,32 +153,27 @@ public class TokenService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response grantAccessToken(final MultivaluedMap<String, String> form) { public Response grantAccessToken(final MultivaluedMap<String, String> form) {
return new Transaction<Response>() { String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
protected Response callImpl() { if (username == null) {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); throw new NotAuthorizedException("No user");
if (username == null) { }
throw new NotAuthorizedException("No user"); if (!realm.isEnabled()) {
} throw new NotAuthorizedException("Disabled realm");
if (!realm.isEnabled()) { }
throw new NotAuthorizedException("Disabled realm"); UserModel user = realm.getUser(username);
} if (user == null) {
UserModel user = realm.getUser(username); throw new NotAuthorizedException("No user");
if (user == null) { }
throw new NotAuthorizedException("No user"); if (!user.isEnabled()) {
} throw new NotAuthorizedException("Disabled user.");
if (!user.isEnabled()) { }
throw new NotAuthorizedException("Disabled user."); if (authManager.authenticateForm(realm, user, form)) {
} throw new NotAuthorizedException("Auth failed");
if (authManager.authenticateForm(realm, user, form)) { }
throw new NotAuthorizedException("Auth failed"); SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
} String encoded = tokenManager.encodeToken(realm, token);
SkeletonKeyToken token = tokenManager.createAccessToken(realm, user); AccessTokenResponse res = accessTokenResponse(token, encoded);
String encoded = tokenManager.encodeToken(realm, token); return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
}
}.call();
} }
@Path("auth/request/login") @Path("auth/request/login")
@ -190,54 +182,50 @@ public class TokenService {
public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam, public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam,
@QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect, @QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect,
final MultivaluedMap<String, String> formData) { final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
protected Response callImpl() {
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
return oauth.forwardToSecurityFailure("Realm not enabled."); return oauth.forwardToSecurityFailure("Realm not enabled.");
} }
UserModel client = realm.getUser(clientId); UserModel client = realm.getUser(clientId);
if (client == null) { if (client == null) {
return oauth.forwardToSecurityFailure("Unknown login requester."); return oauth.forwardToSecurityFailure("Unknown login requester.");
} }
if (!client.isEnabled()) { if (!client.isEnabled()) {
return oauth.forwardToSecurityFailure("Login requester not enabled."); return oauth.forwardToSecurityFailure("Login requester not enabled.");
} }
String username = formData.getFirst("username"); String username = formData.getFirst("username");
UserModel user = realm.getUser(username); UserModel user = realm.getUser(username);
if (user == null) { if (user == null) {
logger.error("Incorrect user name."); logger.error("Incorrect user name.");
return Flows.forms(realm, request).setError(Messages.INVALID_USER).setFormData(formData) return Flows.forms(realm, request).setError(Messages.INVALID_USER).setFormData(formData)
.forwardToLogin(); .forwardToLogin();
}
if (!user.isEnabled()) {
return oauth.forwardToSecurityFailure("Your account is not enabled.");
}
if ("ENABLED".equals(user.getAttribute("KEYCLOAK_TOTP")) && Validation.isEmpty(formData.getFirst("totp"))) {
return Flows.forms(realm, request).setFormData(formData).forwardToLoginTotp();
} else {
for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
if (c.getType().equals(CredentialRepresentation.TOTP)) {
return Flows.forms(realm, request).forwardToTotp();
} }
if (!user.isEnabled()) {
return oauth.forwardToSecurityFailure("Your account is not enabled.");
}
if ("ENABLED".equals(user.getAttribute("KEYCLOAK_TOTP")) && Validation.isEmpty(formData.getFirst("totp"))) {
return Flows.forms(realm, request).setFormData(formData).forwardToLoginTotp();
} else {
for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
if (c.getType().equals(CredentialRepresentation.TOTP)) {
return Flows.forms(realm, request).forwardToTotp();
}
}
}
boolean authenticated = authManager.authenticateForm(realm, user, formData);
if (!authenticated) {
logger.error("Authentication failed");
return Flows.forms(realm, request).setError(Messages.INVALID_PASSWORD).setFormData(formData)
.forwardToLogin();
}
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
} }
}.call(); }
boolean authenticated = authManager.authenticateForm(realm, user, formData);
if (!authenticated) {
logger.error("Authentication failed");
return Flows.forms(realm, request).setError(Messages.INVALID_PASSWORD).setFormData(formData)
.forwardToLogin();
}
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
} }
@Path("registrations") @Path("registrations")
@ -246,20 +234,15 @@ public class TokenService {
public Response processRegister(@QueryParam("client_id") final String clientId, public Response processRegister(@QueryParam("client_id") final String clientId,
@QueryParam("scope") final String scopeParam, @QueryParam("state") final String state, @QueryParam("scope") final String scopeParam, @QueryParam("state") final String state,
@QueryParam("redirect_uri") final String redirect, final MultivaluedMap<String, String> formData) { @QueryParam("redirect_uri") final String redirect, final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { Response registrationResponse = processRegisterImpl(clientId, scopeParam, state, redirect, formData, false);
@Override
protected Response callImpl() {
Response registrationResponse = processRegisterImpl(clientId, scopeParam, state, redirect, formData, false);
// If request has been already forwarded (either due to security or validation error) then we won't continue with login // If request has been already forwarded (either due to security or validation error) then we won't continue with login
if (registrationResponse != null || request.wasForwarded()) { if (registrationResponse != null || request.wasForwarded()) {
logger.warn("Registration attempt wasn't successful. Request already forwarded or redirected."); logger.warn("Registration attempt wasn't successful. Request already forwarded or redirected.");
return registrationResponse; return registrationResponse;
} else { } else {
return processLogin(clientId, scopeParam, state, redirect, formData); return processLogin(clientId, scopeParam, state, redirect, formData);
} }
}
}.call();
} }
public Response processRegisterImpl(String clientId, String scopeParam, String state, String redirect, public Response processRegisterImpl(String clientId, String scopeParam, String state, String redirect,
@ -347,104 +330,99 @@ public class TokenService {
@POST @POST
@Produces("application/json") @Produces("application/json")
public Response accessCodeToToken(final MultivaluedMap<String, String> formData) { public Response accessCodeToToken(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { logger.info("accessRequest <---");
protected Response callImpl() { if (!realm.isEnabled()) {
logger.info("accessRequest <---"); throw new NotAuthorizedException("Realm not enabled");
if (!realm.isEnabled()) { }
throw new NotAuthorizedException("Realm not enabled");
}
String code = formData.getFirst("code"); String code = formData.getFirst("code");
if (code == null) { if (code == null) {
logger.debug("code not specified"); logger.debug("code not specified");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_request"); error.put("error", "invalid_request");
error.put("error_description", "code not specified"); error.put("error_description", "code not specified");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
String client_id = formData.getFirst("client_id"); String client_id = formData.getFirst("client_id");
if (client_id == null) { if (client_id == null) {
logger.debug("client_id not specified"); logger.debug("client_id not specified");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_request"); error.put("error", "invalid_request");
error.put("error_description", "client_id not specified"); error.put("error_description", "client_id not specified");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
UserModel client = realm.getUser(client_id); UserModel client = realm.getUser(client_id);
if (client == null) { if (client == null) {
logger.debug("Could not find user"); logger.debug("Could not find user");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_client"); error.put("error", "invalid_client");
error.put("error_description", "Could not find user"); error.put("error_description", "Could not find user");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
if (!client.isEnabled()) { if (!client.isEnabled()) {
logger.debug("user is not enabled"); logger.debug("user is not enabled");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_client"); error.put("error", "invalid_client");
error.put("error_description", "User is not enabled"); error.put("error_description", "User is not enabled");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
boolean authenticated = authManager.authenticateForm(realm, client, formData); boolean authenticated = authManager.authenticateForm(realm, client, formData);
if (!authenticated) { if (!authenticated) {
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "unauthorized_client"); error.put("error", "unauthorized_client");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false;
try {
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
} catch (Exception ignored) {
logger.debug("Failed to verify signature", ignored);
}
if (!verifiedCode) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Unable to verify code signature");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
String key = input.readContent(String.class);
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
if (accessCode == null) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Code not found");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (accessCode.isExpired()) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Code is expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (!accessCode.getToken().isActive()) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Token expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Auth error");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
logger.info("accessRequest SUCCESS");
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
return Response.ok(res).build();
}
}.call();
JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false;
try {
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
} catch (Exception ignored) {
logger.debug("Failed to verify signature", ignored);
}
if (!verifiedCode) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Unable to verify code signature");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
String key = input.readContent(String.class);
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
if (accessCode == null) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Code not found");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (accessCode.isExpired()) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Code is expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (!accessCode.getToken().isActive()) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Token expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant");
res.put("error_description", "Auth error");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
logger.info("accessRequest SUCCESS");
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
return Response.ok(res).build();
} }
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) { protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
@ -475,47 +453,43 @@ public class TokenService {
public Response loginPage(final @QueryParam("response_type") String responseType, public Response loginPage(final @QueryParam("response_type") String responseType,
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId, final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) { final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
return new Transaction<Response>() { OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
protected Response callImpl() {
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
oauth.forwardToSecurityFailure("Realm not enabled"); oauth.forwardToSecurityFailure("Realm not enabled");
return null; return null;
} }
UserModel client = realm.getUser(clientId); UserModel client = realm.getUser(clientId);
if (client == null) { if (client == null) {
oauth.forwardToSecurityFailure("Unknown login requester."); oauth.forwardToSecurityFailure("Unknown login requester.");
transaction.rollback(); transaction.rollback();
return null; return null;
} }
if (!client.isEnabled()) { if (!client.isEnabled()) {
oauth.forwardToSecurityFailure("Login requester not enabled."); oauth.forwardToSecurityFailure("Login requester not enabled.");
transaction.rollback(); transaction.rollback();
session.close(); session.close();
return null; return null;
} }
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE); RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE); RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.hasRole(client, resourceRole); boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) { if (!isResource && !realm.hasRole(client, identityRequestRole)) {
oauth.forwardToSecurityFailure("Login requester not allowed to request login."); oauth.forwardToSecurityFailure("Login requester not allowed to request login.");
transaction.rollback(); transaction.rollback();
session.close(); session.close();
return null; return null;
} }
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) { if (user != null) {
logger.info(user.getLoginName() + " already logged in."); logger.info(user.getLoginName() + " already logged in.");
return oauth.processAccessCode(scopeParam, state, redirect, client, user); return oauth.processAccessCode(scopeParam, state, redirect, client, user);
} }
return Flows.forms(realm, request).forwardToLogin(); return Flows.forms(realm, request).forwardToLogin();
}
}.call();
} }
@Path("registrations") @Path("registrations")
@ -523,88 +497,76 @@ public class TokenService {
public Response registerPage(final @QueryParam("response_type") String responseType, public Response registerPage(final @QueryParam("response_type") String responseType,
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId, final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) { final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
return new Transaction<Response>() { OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
protected Response callImpl() {
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
return oauth.forwardToSecurityFailure("Realm not enabled"); return oauth.forwardToSecurityFailure("Realm not enabled");
} }
UserModel client = realm.getUser(clientId); UserModel client = realm.getUser(clientId);
if (client == null) { if (client == null) {
return oauth.forwardToSecurityFailure("Unknown login requester."); return oauth.forwardToSecurityFailure("Unknown login requester.");
} }
if (!client.isEnabled()) { if (!client.isEnabled()) {
return oauth.forwardToSecurityFailure("Login requester not enabled."); return oauth.forwardToSecurityFailure("Login requester not enabled.");
} }
if (!realm.isRegistrationAllowed()) { if (!realm.isRegistrationAllowed()) {
return oauth.forwardToSecurityFailure("Registration not allowed"); return oauth.forwardToSecurityFailure("Registration not allowed");
} }
authManager.expireIdentityCookie(realm, uriInfo); authManager.expireIdentityCookie(realm, uriInfo);
return Flows.forms(realm, request).forwardToRegistration(); return Flows.forms(realm, request).forwardToRegistration();
}
}.call();
} }
@Path("logout") @Path("logout")
@GET @GET
@NoCache @NoCache
public Response logout(final @QueryParam("redirect_uri") String redirectUri) { public Response logout(final @QueryParam("redirect_uri") String redirectUri) {
return new Transaction<Response>() { // todo do we care if anybody can trigger this?
protected Response callImpl() {
// todo do we care if anybody can trigger this?
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers); UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) { if (user != null) {
logger.info("Logging out: " + user.getLoginName()); logger.info("Logging out: " + user.getLoginName());
authManager.expireIdentityCookie(realm, uriInfo); authManager.expireIdentityCookie(realm, uriInfo);
resourceAdminManager.singleLogOut(realm, user.getLoginName()); resourceAdminManager.singleLogOut(realm, user.getLoginName());
} }
// todo manage legal redirects // todo manage legal redirects
return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build(); return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
}
}.call();
} }
@Path("oauth/grant") @Path("oauth/grant")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processOAuth(final MultivaluedMap<String, String> formData) { public Response processOAuth(final MultivaluedMap<String, String> formData) {
return new Transaction<Response>() { OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
protected Response callImpl() {
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
String code = formData.getFirst("code"); String code = formData.getFirst("code");
JWSInput input = new JWSInput(code, providers); JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false; boolean verifiedCode = false;
try { try {
verifiedCode = RSAProvider.verify(input, realm.getPublicKey()); verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
} catch (Exception ignored) { } catch (Exception ignored) {
logger.debug("Failed to verify signature", ignored); logger.debug("Failed to verify signature", ignored);
} }
if (!verifiedCode) { if (!verifiedCode) {
return oauth.forwardToSecurityFailure("Illegal access code."); return oauth.forwardToSecurityFailure("Illegal access code.");
} }
String key = input.readContent(String.class); String key = input.readContent(String.class);
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key); AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
if (accessCodeEntry == null) { if (accessCodeEntry == null) {
return oauth.forwardToSecurityFailure("Unknown access code."); return oauth.forwardToSecurityFailure("Unknown access code.");
} }
String redirect = accessCodeEntry.getRedirectUri(); String redirect = accessCodeEntry.getRedirectUri();
String state = accessCodeEntry.getState(); String state = accessCodeEntry.getState();
if (formData.containsKey("cancel")) { if (formData.containsKey("cancel")) {
return redirectAccessDenied(redirect, state); return redirectAccessDenied(redirect, state);
} }
return oauth.redirectAccessCode(accessCodeEntry, state, redirect); return oauth.redirectAccessCode(accessCodeEntry, state, redirect);
}
}.call();
} }
protected Response redirectAccessDenied(String redirect, String state) { protected Response redirectAccessDenied(String redirect, String state) {

View file

@ -2,17 +2,15 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.services.models.KeycloakSession; import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.KeycloakTransaction; import org.keycloak.services.models.KeycloakTransaction;
import javax.ws.rs.core.Application;
/** /**
* Meant to be used as an inner class wrapper (I forget the pattern name, its been awhile). * Meant to be used as an inner class wrapper (I forget the pattern name, its been awhile).
* *
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Deprecated
public class Transaction<T> { public class Transaction<T> {
protected KeycloakSession session; protected KeycloakSession session;
protected KeycloakTransaction transaction; protected KeycloakTransaction transaction;
@ -36,6 +34,8 @@ public class Transaction<T> {
*/ */
public Transaction(boolean close) { public Transaction(boolean close) {
this.session = ResteasyProviderFactory.getContextData(KeycloakSession.class); this.session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
this.transaction = session.getTransaction();
/*
if (session == null) { if (session == null) {
KeycloakApplication app = (KeycloakApplication)ResteasyProviderFactory.getContextData(Application.class); KeycloakApplication app = (KeycloakApplication)ResteasyProviderFactory.getContextData(Application.class);
session = app.getFactory().createSession(); session = app.getFactory().createSession();
@ -44,20 +44,10 @@ public class Transaction<T> {
} }
transaction = session.getTransaction(); transaction = session.getTransaction();
closeSession = close; closeSession = close;
*/
} }
/**
* Creates and manages its own session.
*
* @param factory
*/
public Transaction(KeycloakSessionFactory factory) {
this.closeSession = true;
this.session = factory.createSession();
this.transaction = session.getTransaction();
}
protected void runImpl() { protected void runImpl() {
} }
@ -67,20 +57,20 @@ public class Transaction<T> {
* *
*/ */
public void run() { public void run() {
boolean wasActive = transaction.isActive(); // boolean wasActive = transaction.isActive();
if (!wasActive) transaction.begin(); // if (!wasActive) transaction.begin();
try { // try {
runImpl(); runImpl();
if (!wasActive && transaction.isActive()) transaction.commit(); // if (!wasActive && transaction.isActive()) transaction.commit();
} catch (RuntimeException e) { // } catch (RuntimeException e) {
if (!wasActive && transaction.isActive()) transaction.rollback(); // if (!wasActive && transaction.isActive()) transaction.rollback();
if (created) closeSession = true; // if (created) closeSession = true;
throw e; // throw e;
} finally { // } finally {
if (!wasActive && closeSession) { // if (!wasActive && closeSession) {
session.close(); // session.close();
} // }
} // }
} }
protected T callImpl() { protected T callImpl() {
@ -92,18 +82,18 @@ public class Transaction<T> {
* *
*/ */
public T call() { public T call() {
boolean wasActive = transaction.isActive(); // boolean wasActive = transaction.isActive();
if (!wasActive) transaction.begin(); // if (!wasActive) transaction.begin();
try { // try {
T rtn = callImpl(); T rtn = callImpl();
if (!wasActive && transaction.isActive()) transaction.commit(); // if (!wasActive && transaction.isActive()) transaction.commit();
return rtn; return rtn;
} catch (RuntimeException e) { // } catch (RuntimeException e) {
if (!wasActive && transaction.isActive()) transaction.rollback(); // if (!wasActive && transaction.isActive()) transaction.rollback();
if (created) closeSession = true; // close if there was a failure // if (created) closeSession = true; // close if there was a failure
throw e; // throw e;
} finally { // } finally {
if (!wasActive && closeSession) session.close(); // if (!wasActive && closeSession) session.close();
} // }
} }
} }

View file

@ -5,16 +5,13 @@ import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceManager; import org.keycloak.services.managers.ResourceManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ApplicationModel; import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.GET; import javax.ws.rs.core.Context;
import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
/** /**
@ -27,6 +24,9 @@ public class ApplicationResource {
protected RealmModel realm; protected RealmModel realm;
protected ApplicationModel applicationModel; protected ApplicationModel applicationModel;
@Context
protected KeycloakSession session;
public ApplicationResource(UserModel admin, RealmModel realm, ApplicationModel applicationModel) { public ApplicationResource(UserModel admin, RealmModel realm, ApplicationModel applicationModel) {
this.admin = admin; this.admin = admin;
this.realm = realm; this.realm = realm;
@ -36,13 +36,8 @@ public class ApplicationResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void update(final ApplicationRepresentation rep) { public void update(final ApplicationRepresentation rep) {
new Transaction<Void>() { ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
@Override resourceManager.updateResource(rep, applicationModel);
protected void runImpl() {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
resourceManager.updateResource(rep, applicationModel);
}
}.run();
} }
@ -50,12 +45,7 @@ public class ApplicationResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ApplicationRepresentation getResource(final @PathParam("id") String id) { public ApplicationRepresentation getResource(final @PathParam("id") String id) {
return new Transaction<ApplicationRepresentation>() { ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
@Override return resourceManager.toRepresentation(applicationModel);
protected ApplicationRepresentation callImpl() {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
return resourceManager.toRepresentation(applicationModel);
}
}.call();
} }
} }

View file

@ -5,18 +5,13 @@ import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceManager; import org.keycloak.services.managers.ResourceManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ApplicationModel; import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.GET; import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -33,6 +28,12 @@ public class ApplicationsResource {
protected UserModel admin; protected UserModel admin;
protected RealmModel realm; protected RealmModel realm;
@Context
protected ResourceContext resourceContext;
@Context
protected KeycloakSession session;
public ApplicationsResource(UserModel admin, RealmModel realm) { public ApplicationsResource(UserModel admin, RealmModel realm) {
this.admin = admin; this.admin = admin;
this.realm = realm; this.realm = realm;
@ -42,46 +43,32 @@ public class ApplicationsResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<ApplicationRepresentation> getResources() { public List<ApplicationRepresentation> getResources() {
return new Transaction<List<ApplicationRepresentation>>() { List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>();
@Override List<ApplicationModel> applicationModels = realm.getApplications();
protected List<ApplicationRepresentation> callImpl() { ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>(); for (ApplicationModel applicationModel : applicationModels) {
List<ApplicationModel> applicationModels = realm.getApplications(); rep.add(resourceManager.toRepresentation(applicationModel));
ResourceManager resourceManager = new ResourceManager(new RealmManager(session)); }
for (ApplicationModel applicationModel : applicationModels) { return rep;
rep.add(resourceManager.toRepresentation(applicationModel));
}
return rep;
}
}.call();
} }
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createResource(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) { public Response createResource(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) {
return new Transaction<Response>() { ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
@Override ApplicationModel applicationModel = resourceManager.createResource(realm, rep);
protected Response callImpl() { return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getId()).build()).build();
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
ApplicationModel applicationModel = resourceManager.createResource(realm, rep);
return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getId()).build()).build();
}
}.call();
} }
@Path("{id}") @Path("{id}")
public ApplicationResource getResource(final @PathParam("id") String id) { public ApplicationResource getResource(final @PathParam("id") String id) {
return new Transaction<ApplicationResource>(false) { ApplicationModel applicationModel = realm.getApplicationById(id);
@Override if (applicationModel == null) {
protected ApplicationResource callImpl() { throw new NotFoundException();
ApplicationModel applicationModel = realm.getApplicationById(id); }
if (applicationModel == null) { ApplicationResource applicationResource = new ApplicationResource(admin, realm, applicationModel);
throw new NotFoundException(); resourceContext.initResource(applicationResource);
} return applicationResource;
return new ApplicationResource(admin, realm, applicationModel);
}
}.call();
} }
} }

View file

@ -6,20 +6,13 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel; import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.GET; import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@ -35,6 +28,12 @@ public class RealmAdminResource {
protected UserModel admin; protected UserModel admin;
protected RealmModel realm; protected RealmModel realm;
@Context
protected ResourceContext resourceContext;
@Context
protected KeycloakSession session;
public RealmAdminResource(UserModel admin, RealmModel realm) { public RealmAdminResource(UserModel admin, RealmModel realm) {
this.admin = admin; this.admin = admin;
this.realm = realm; this.realm = realm;
@ -42,19 +41,16 @@ public class RealmAdminResource {
@Path("applications") @Path("applications")
public ApplicationsResource getResources() { public ApplicationsResource getResources() {
return new ApplicationsResource(admin, realm); ApplicationsResource applicationsResource = new ApplicationsResource(admin, realm);
resourceContext.initResource(applicationsResource);
return applicationsResource;
} }
@GET @GET
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
public RealmRepresentation getRealm() { public RealmRepresentation getRealm() {
return new Transaction<RealmRepresentation>() { return new RealmManager(session).toRepresentation(realm);
@Override
protected RealmRepresentation callImpl() {
return new RealmManager(session).toRepresentation(realm);
}
}.call();
} }
@ -63,31 +59,20 @@ public class RealmAdminResource {
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
public List<RoleRepresentation> getRoles() { public List<RoleRepresentation> getRoles() {
return new Transaction<List<RoleRepresentation>>() { List<RoleModel> roleModels = realm.getRoles();
@Override List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
protected List<RoleRepresentation> callImpl() { for (RoleModel roleModel : roleModels) {
List<RoleModel> roleModels = realm.getRoles(); RoleRepresentation role = new RoleRepresentation(roleModel.getName(), roleModel.getDescription());
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>(); roles.add(role);
for (RoleModel roleModel : roleModels) { }
RoleRepresentation role = new RoleRepresentation(roleModel.getName(), roleModel.getDescription()); return roles;
roles.add(role);
}
return roles;
}
}.call();
} }
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
public void updateRealm(final RealmRepresentation rep) { public void updateRealm(final RealmRepresentation rep) {
new Transaction() { logger.info("updating realm: " + rep.getRealm());
@Override new RealmManager(session).updateRealm(rep, realm);
protected void runImpl() {
logger.info("updating realm: " + rep.getRealm());
new RealmManager(session).updateRealm(rep, realm);
}
}.run();
} }
@Path("roles/{id}") @Path("roles/{id}")
@ -95,18 +80,13 @@ public class RealmAdminResource {
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
public RoleRepresentation getRole(final @PathParam("id") String id) { public RoleRepresentation getRole(final @PathParam("id") String id) {
return new Transaction<RoleRepresentation>() { RoleModel roleModel = realm.getRoleById(id);
@Override if (roleModel == null) {
protected RoleRepresentation callImpl() { throw new NotFoundException();
RoleModel roleModel = realm.getRoleById(id); }
if (roleModel == null) { RoleRepresentation rep = new RoleRepresentation(roleModel.getName(), roleModel.getDescription());
throw new NotFoundException(); rep.setId(roleModel.getId());
} return rep;
RoleRepresentation rep = new RoleRepresentation(roleModel.getName(), roleModel.getDescription());
rep.setId(roleModel.getId());
return rep;
}
}.call();
} }
@ -114,39 +94,27 @@ public class RealmAdminResource {
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
public void updateRole(final @PathParam("id") String id, final RoleRepresentation rep) { public void updateRole(final @PathParam("id") String id, final RoleRepresentation rep) {
new Transaction() { RoleModel role = realm.getRoleById(id);
@Override if (role == null) {
protected void runImpl() { throw new NotFoundException();
RoleModel role = realm.getRoleById(id); }
if (role == null) { role.setName(rep.getName());
throw new NotFoundException(); role.setDescription(rep.getDescription());
}
role.setName(rep.getName());
role.setDescription(rep.getDescription());
}
}.run();
} }
@Path("roles") @Path("roles")
@POST @POST
@Consumes("application/json") @Consumes("application/json")
public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) { public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) {
return new Transaction<Response>() { if (realm.getRole(rep.getName()) != null) {
@Override throw new InternalServerErrorException(); // todo appropriate status here.
protected Response callImpl() { }
if (realm.getRole(rep.getName()) != null) { RoleModel role = realm.addRole(rep.getName());
throw new InternalServerErrorException(); // todo appropriate status here. if (role == null) {
} throw new NotFoundException();
RoleModel role = realm.addRole(rep.getName()); }
if (role == null) { role.setDescription(rep.getDescription());
throw new NotFoundException(); return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getId()).build()).build();
}
role.setDescription(rep.getDescription());
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getId()).build()).build();
}
}.call();
} }

View file

@ -4,34 +4,17 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.PublicRealmResource;
import org.keycloak.services.resources.SaasService; import org.keycloak.services.resources.SaasService;
import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.ForbiddenException; import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.GET; import javax.ws.rs.core.*;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -50,23 +33,24 @@ public class RealmsAdminResource {
noCache.setNoCache(true); noCache.setNoCache(true);
} }
@Context
protected ResourceContext resourceContext;
@Context
protected KeycloakSession session;
@GET @GET
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
public List<RealmRepresentation> getRealms() { public List<RealmRepresentation> getRealms() {
return new Transaction<List<RealmRepresentation>>() { logger.info(("getRealms()"));
@Override RealmManager realmManager = new RealmManager(session);
protected List<RealmRepresentation> callImpl() { List<RealmModel> realms = session.getRealms(admin);
logger.info(("getRealms()")); List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
RealmManager realmManager = new RealmManager(session); for (RealmModel realm : realms) {
List<RealmModel> realms = session.getRealms(admin); reps.add(realmManager.toRepresentation(realm));
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>(); }
for (RealmModel realm : realms) { return reps;
reps.add(realmManager.toRepresentation(realm));
}
return reps;
}
}.call();
} }
public static UriBuilder realmUrl(UriInfo uriInfo) { public static UriBuilder realmUrl(UriInfo uriInfo) {
@ -81,34 +65,26 @@ public class RealmsAdminResource {
@Consumes("application/json") @Consumes("application/json")
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) { public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
logger.info("importRealm: " + rep.getRealm()); logger.info("importRealm: " + rep.getRealm());
return new Transaction<Response>() { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.importRealm(rep, admin);
protected Response callImpl() { URI location = realmUrl(uriInfo).build(realm.getId());
RealmManager realmManager = new RealmManager(session); logger.info("imported realm success, sending back: " + location.toString());
RealmModel realm = realmManager.importRealm(rep, admin); return Response.created(location).build();
URI location = realmUrl(uriInfo).build(realm.getId());
logger.info("imported realm success, sending back: " + location.toString());
return Response.created(location).build();
}
}.call();
} }
@Path("{id}") @Path("{id}")
public RealmAdminResource getRealmAdmin(@Context final HttpHeaders headers, public RealmAdminResource getRealmAdmin(@Context final HttpHeaders headers,
@PathParam("id") final String id) { @PathParam("id") final String id) {
return new Transaction<RealmAdminResource>(false) { RealmManager realmManager = new RealmManager(session);
@Override RealmModel realm = realmManager.getRealm(id);
protected RealmAdminResource callImpl() { if (realm == null) throw new NotFoundException();
RealmManager realmManager = new RealmManager(session); if (!realm.isRealmAdmin(admin)) {
RealmModel realm = realmManager.getRealm(id); throw new ForbiddenException();
if (realm == null) throw new NotFoundException(); }
if (!realm.isRealmAdmin(admin)) {
throw new ForbiddenException();
}
return new RealmAdminResource(admin, realm); RealmAdminResource adminResource = new RealmAdminResource(admin, realm);
} resourceContext.initResource(adminResource);
}.call(); return adminResource;
} }

View file

@ -21,13 +21,13 @@
*/ */
package org.keycloak.services.resources.flows; package org.keycloak.services.resources.flows;
import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import javax.ws.rs.core.UriInfo;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */

View file

@ -21,14 +21,14 @@
*/ */
package org.keycloak.services.resources.flows; package org.keycloak.services.resources.flows;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.picketlink.idm.model.sample.Realm; import org.picketlink.idm.model.sample.Realm;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */

View file

@ -21,10 +21,6 @@
*/ */
package org.keycloak.services.resources.flows; package org.keycloak.services.resources.flows;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.services.managers.AccessCodeEntry; import org.keycloak.services.managers.AccessCodeEntry;
@ -36,6 +32,10 @@ import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.TokenService; import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>

View file

@ -21,12 +21,12 @@
*/ */
package org.keycloak.services.resources.flows; package org.keycloak.services.resources.flows;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.services.JspRequestParameters; import org.keycloak.services.JspRequestParameters;
import javax.ws.rs.core.Response;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */

View file

@ -21,15 +21,10 @@
*/ */
package org.keycloak.services.resources.flows; package org.keycloak.services.resources.flows;
import java.net.URI; import org.keycloak.services.resources.*;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.SaasService;
import org.keycloak.services.resources.SocialResource;
import org.keycloak.services.resources.TokenService;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>

View file

@ -1,12 +1,11 @@
package org.keycloak.services.validation; package org.keycloak.services.validation;
import java.util.List;
import javax.ws.rs.core.MultivaluedMap;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import java.util.List;
public class Validation { public class Validation {
public static String validateRegistrationForm(MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes) { public static String validateRegistrationForm(MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes) {

View file

@ -0,0 +1,70 @@
package org.keycloak.test;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.resources.KeycloakApplication;
import javax.servlet.DispatcherType;
import javax.ws.rs.client.Client;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AbstractKeycloakServerTest {
public static UndertowJaxrsServer server;
public static ResteasyDeployment deployment;
public static Client client;
public static KeycloakApplication application;
@BeforeClass
public static void undertowSetup() throws Exception {
deployment = new ResteasyDeployment();
deployment.setApplicationClass(KeycloakApplication.class.getName());
server = new UndertowJaxrsServer().start();
DeploymentInfo di = server.undertowDeployment(deployment);
di.setClassLoader(AbstractKeycloakServerTest.class.getClassLoader());
di.setContextPath("/");
di.setDeploymentName("Keycloak");
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
di.addFilter(filter);
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
server.deploy(di);
application = (KeycloakApplication) deployment.getApplication();
client = new ResteasyClientBuilder().connectionPoolSize(10).build();
client.register(SkeletonKeyContextResolver.class);
}
@AfterClass
public static void undertowShutdown() throws Exception {
server.stop();
}
public static RealmRepresentation loadJson(String path) throws IOException {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ((c = is.read()) != -1) {
os.write(c);
}
byte[] bytes = os.toByteArray();
System.out.println(new String(bytes));
return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
}
}

View file

@ -66,7 +66,7 @@ public class ImportTest {
UserModel admin = defaultRealm.addUser("admin"); UserModel admin = defaultRealm.addUser("admin");
defaultRealm.grantRole(admin, role); defaultRealm.grantRole(admin, role);
RealmRepresentation rep = KeycloakTestBase.loadJson("testrealm.json"); RealmRepresentation rep = AbstractKeycloakServerTest.loadJson("testrealm.json");
RealmModel realm = manager.createRealm("demo", rep.getRealm()); RealmModel realm = manager.createRealm("demo", rep.getRealm());
manager.importRealm(rep, realm); manager.importRealm(rep, realm);
realm.addRealmAdmin(admin); realm.addRealmAdmin(admin);
@ -141,7 +141,7 @@ public class ImportTest {
UserModel admin = defaultRealm.addUser("admin"); UserModel admin = defaultRealm.addUser("admin");
defaultRealm.grantRole(admin, role); defaultRealm.grantRole(admin, role);
RealmRepresentation rep = KeycloakTestBase.loadJson("testrealm-demo.json"); RealmRepresentation rep = AbstractKeycloakServerTest.loadJson("testrealm-demo.json");
RealmModel realm = manager.createRealm("demo", rep.getRealm()); RealmModel realm = manager.createRealm("demo", rep.getRealm());
manager.importRealm(rep, realm); manager.importRealm(rep, realm);
realm.addRealmAdmin(admin); realm.addRealmAdmin(admin);

View file

@ -1,31 +0,0 @@
package org.keycloak.test;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.test.BaseResourceTest;
import org.keycloak.representations.idm.RealmRepresentation;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakTestBase extends BaseResourceTest
{
public static RealmRepresentation loadJson(String path) throws IOException
{
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ( (c = is.read()) != -1)
{
os.write(c);
}
byte[] bytes = os.toByteArray();
System.out.println(new String(bytes));
return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
}
}

View file

@ -1,12 +1,8 @@
package org.keycloak.test; package org.keycloak.test;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.test.EmbeddedContainer;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -15,10 +11,8 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession; import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.resources.KeycloakApplication;
import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;
@ -31,30 +25,16 @@ import static org.jboss.resteasy.test.TestPortProvider.generateURL;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmCreationTest { public class RealmCreationTest extends AbstractKeycloakServerTest {
private static ResteasyDeployment deployment;
private static Client client;
@BeforeClass @BeforeClass
public static void before() throws Exception { public static void before() throws Exception {
deployment = new ResteasyDeployment();
deployment.setApplicationClass(KeycloakApplication.class.getName());
EmbeddedContainer.start(deployment);
KeycloakApplication application = (KeycloakApplication) deployment.getApplication();
KeycloakSession session = application.getFactory().createSession(); KeycloakSession session = application.getFactory().createSession();
session.getTransaction().begin(); session.getTransaction().begin();
RealmManager manager = new RealmManager(session); RealmManager manager = new RealmManager(session);
new InstallationManager().install(manager); new InstallationManager().install(manager);
session.getTransaction().commit(); session.getTransaction().commit();
session.close(); session.close();
client = new ResteasyClientBuilder().build();
client.register(SkeletonKeyContextResolver.class);
}
public static void after() throws Exception {
client.close();
EmbeddedContainer.stop();
} }
@Test @Test
@ -86,7 +66,7 @@ public class RealmCreationTest {
System.out.println(tokenResponse.getToken()); System.out.println(tokenResponse.getToken());
// //
RealmRepresentation realm = KeycloakTestBase.loadJson("testrealm.json"); RealmRepresentation realm = loadJson("testrealm.json");
response = target.path("saas/admin/realms").request().header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getToken()).post(Entity.json(realm)); response = target.path("saas/admin/realms").request().header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getToken()).post(Entity.json(realm));
Assert.assertEquals(201, response.getStatus()); Assert.assertEquals(201, response.getStatus());
response.close(); response.close();