KEYCLOAK-292 Fine-grained admin control
This commit is contained in:
parent
7f33593931
commit
9a73936002
35 changed files with 781 additions and 589 deletions
|
@ -7,6 +7,17 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
|
||||||
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
|
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
|
||||||
Auth.user = data;
|
Auth.user = data;
|
||||||
Auth.loggedIn = true;
|
Auth.loggedIn = true;
|
||||||
|
|
||||||
|
Auth.hasAccess = function(realm, role) {
|
||||||
|
var realmAccess = Auth.user['realm_access'];
|
||||||
|
if (realmAccess) {
|
||||||
|
realmAccess = realmAccess[realm];
|
||||||
|
if (realmAccess) {
|
||||||
|
return realmAccess.indexOf(role) >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
Auth.loggedIn = false;
|
Auth.loggedIn = false;
|
||||||
|
@ -62,7 +73,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications) {
|
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications, Auth) {
|
||||||
console.log('RealmCreateCtrl');
|
console.log('RealmCreateCtrl');
|
||||||
|
|
||||||
Current.realm = null;
|
Current.realm = null;
|
||||||
|
@ -131,10 +142,16 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||||
Current.realm = Current.realms[i];
|
Current.realm = Current.realms[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
|
||||||
|
Auth.user = data;
|
||||||
|
console.log("reloaded auth");
|
||||||
|
|
||||||
$location.url("/realms/" + realmCopy.realm);
|
$location.url("/realms/" + realmCopy.realm);
|
||||||
Notifications.success("The realm has been created.");
|
Notifications.success("The realm has been created.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.cancel = function() {
|
$scope.cancel = function() {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="active pull-right" data-ng-show="auth.loggedIn">
|
<li class="active pull-right" data-ng-show="auth.loggedIn && auth.user.admin">
|
||||||
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
||||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
||||||
<li class="active">General</li>
|
<li class="active">General</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
<div data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')">
|
||||||
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</h2>
|
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</h2>
|
||||||
<h2 data-ng-hide="createRealm"><span>{{realm.realm}}</span> General Settings</h2>
|
<h2 data-ng-hide="createRealm"><span>{{realm.realm}}</span> General Settings</h2>
|
||||||
<p class="subtitle" data-ng-show="createRealm"><span class="required">*</span> Required fields</p>
|
<p class="subtitle" data-ng-show="createRealm"><span class="required">*</span> Required fields</p>
|
||||||
|
@ -101,4 +102,9 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div data-ng-hide="auth.hasAccess(realm.realm, 'manage-realm')">
|
||||||
|
<h2 ><span>{{realm.realm}}</span></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,10 +1,9 @@
|
||||||
<ul data-ng-hide="createRealm">
|
<ul data-ng-hide="createRealm">
|
||||||
<li data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
|
<li data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')" data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
|
||||||
path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'default-roles' || path[2] == 'registration-settings' ||
|
path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'default-roles' || path[2] == 'registration-settings' ||
|
||||||
path[2] == 'keys-settings' || path[2] == 'smtp-settings') && path[3] != 'applications') && 'active'"><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
path[2] == 'keys-settings' || path[2] == 'smtp-settings') && path[3] != 'applications') && 'active'"><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
||||||
<li data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
|
<li data-ng-show="auth.hasAccess(realm.realm, 'manage-users')" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
|
||||||
</li>
|
</li>
|
||||||
<li data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
|
<li data-ng-show="auth.hasAccess(realm.realm, 'manage-applications')" data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
|
||||||
<li data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
|
<li data-ng-show="auth.hasAccess(realm.realm, 'manage-clients')" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<ul class="nav nav-tabs nav-tabs-pf">
|
<ul class="nav nav-tabs nav-tabs-pf">
|
||||||
<li ng-class="{active: kcCurrent == 'general'}"><a href="#/realms/{{kcRealm}}">General</a></li>
|
<li ng-class="{active: kcCurrent == 'general'}"><a href="#/realms/{{kcRealm}}">General</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'social'}" data-ng-show="kcSocial"><a href="#/realms/{{kcRealm}}/social-settings">Social</a></li>
|
<li ng-class="{active: kcCurrent == 'social'}" data-ng-show="kcSocial && auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/social-settings">Social</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'roles'}"><a href="#/realms/{{kcRealm}}/roles">Roles</a></li>
|
<li ng-class="{active: kcCurrent == 'roles'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/roles">Roles</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'defRoles'}"><a href="#/realms/{{kcRealm}}/default-roles">Default Roles</a></li>
|
<li ng-class="{active: kcCurrent == 'defRoles'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/default-roles">Default Roles</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'credentials'}"><a href="#/realms/{{kcRealm}}/required-credentials">Credentials</a></li>
|
<li ng-class="{active: kcCurrent == 'credentials'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/required-credentials">Credentials</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'token'}"><a href="#/realms/{{kcRealm}}/token-settings">Token</a></li>
|
<li ng-class="{active: kcCurrent == 'token'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/token-settings">Token</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'keys'}"><a href="#/realms/{{kcRealm}}/keys-settings">Keys</a></li>
|
<li ng-class="{active: kcCurrent == 'keys'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/keys-settings">Keys</a></li>
|
||||||
<li ng-class="{active: kcCurrent == 'email'}"><a href="#/realms/{{kcRealm}}/smtp-settings">Email</a></li>
|
<li ng-class="{active: kcCurrent == 'email'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/smtp-settings">Email</a></li>
|
||||||
</ul>
|
</ul>
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface AccountRoles {
|
||||||
|
|
||||||
|
String VIEW_PROFILE = "view-profile";
|
||||||
|
String MANAGE_ACCOUNT = "manage-account";
|
||||||
|
|
||||||
|
String[] ALL = {VIEW_PROFILE, MANAGE_ACCOUNT};
|
||||||
|
|
||||||
|
}
|
23
model/api/src/main/java/org/keycloak/models/AdminRoles.java
Normal file
23
model/api/src/main/java/org/keycloak/models/AdminRoles.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class AdminRoles {
|
||||||
|
|
||||||
|
public static String APP_SUFFIX = "-realm";
|
||||||
|
|
||||||
|
public static String ADMIN = "admin";
|
||||||
|
|
||||||
|
public static String MANAGE_REALM = "manage-realm";
|
||||||
|
public static String MANAGE_USERS = "manage-users";
|
||||||
|
public static String MANAGE_APPLICATIONS = "manage-applications";
|
||||||
|
public static String MANAGE_CLIENTS = "manage-clients";
|
||||||
|
|
||||||
|
public static String[] ALL_REALM_ROLES = {MANAGE_REALM, MANAGE_USERS, MANAGE_APPLICATIONS, MANAGE_CLIENTS};
|
||||||
|
|
||||||
|
public static String getAdminApp(RealmModel realm) {
|
||||||
|
return realm.getName() + APP_SUFFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,14 +5,12 @@ package org.keycloak.models;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface Constants {
|
public interface Constants {
|
||||||
String INTERNAL_ROLE = "KEYCLOAK_";
|
|
||||||
String ADMIN_REALM = "keycloak-admin";
|
String ADMIN_REALM = "keycloak-admin";
|
||||||
String ADMIN_CONSOLE_APPLICATION = "admin-console";
|
String ADMIN_CONSOLE_APPLICATION = "admin-console";
|
||||||
String ADMIN_CONSOLE_ADMIN_ROLE = "admin";
|
|
||||||
|
String INTERNAL_ROLE = "KEYCLOAK_";
|
||||||
String APPLICATION_ROLE = INTERNAL_ROLE + "_APPLICATION";
|
String APPLICATION_ROLE = INTERNAL_ROLE + "_APPLICATION";
|
||||||
String IDENTITY_REQUESTER_ROLE = INTERNAL_ROLE + "_IDENTITY_REQUESTER";
|
String IDENTITY_REQUESTER_ROLE = INTERNAL_ROLE + "_IDENTITY_REQUESTER";
|
||||||
|
|
||||||
String ACCOUNT_APPLICATION = "account";
|
String ACCOUNT_MANAGEMENT_APP = "account";
|
||||||
String ACCOUNT_PROFILE_ROLE = "view-profile";
|
|
||||||
String ACCOUNT_MANAGE_ROLE = "manage-account";
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public interface KeycloakSession {
|
||||||
RealmModel createRealm(String id, String name);
|
RealmModel createRealm(String id, String name);
|
||||||
RealmModel getRealm(String id);
|
RealmModel getRealm(String id);
|
||||||
RealmModel getRealmByName(String name);
|
RealmModel getRealmByName(String name);
|
||||||
List<RealmModel> getRealms(UserModel admin);
|
List<RealmModel> getRealms();
|
||||||
boolean removeRealm(String id);
|
boolean removeRealm(String id);
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class JpaKeycloakSession implements KeycloakSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RealmModel> getRealms(UserModel admin) {
|
public List<RealmModel> getRealms() {
|
||||||
TypedQuery<RealmEntity> query = em.createNamedQuery("getAllRealms", RealmEntity.class);
|
TypedQuery<RealmEntity> query = em.createNamedQuery("getAllRealms", RealmEntity.class);
|
||||||
List<RealmEntity> entities = query.getResultList();
|
List<RealmEntity> entities = query.getResultList();
|
||||||
List<RealmModel> realms = new ArrayList<RealmModel>();
|
List<RealmModel> realms = new ArrayList<RealmModel>();
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class MongoKeycloakSession implements KeycloakSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RealmModel> getRealms(UserModel admin) {
|
public List<RealmModel> getRealms() {
|
||||||
DBObject query = new BasicDBObject();
|
DBObject query = new BasicDBObject();
|
||||||
List<RealmEntity> realms = getMongoStore().loadEntities(RealmEntity.class, query, invocationContext);
|
List<RealmEntity> realms = getMongoStore().loadEntities(RealmEntity.class, query, invocationContext);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
@ -34,6 +35,8 @@ public class AbstractModelTest {
|
||||||
identitySession = factory.createSession();
|
identitySession = factory.createSession();
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
realmManager = new RealmManager(identitySession);
|
realmManager = new RealmManager(identitySession);
|
||||||
|
|
||||||
|
new ApplianceBootstrap().bootstrap(identitySession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.model.test;
|
package org.keycloak.model.test;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.FixMethodOrder;
|
import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
|
@ -32,12 +33,6 @@ import java.util.Set;
|
||||||
public class AdapterTest extends AbstractModelTest {
|
public class AdapterTest extends AbstractModelTest {
|
||||||
private RealmModel realmModel;
|
private RealmModel realmModel;
|
||||||
|
|
||||||
@Test
|
|
||||||
public void installTest() throws Exception {
|
|
||||||
new ApplianceBootstrap().bootstrap(identitySession);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test1CreateRealm() throws Exception {
|
public void test1CreateRealm() throws Exception {
|
||||||
realmModel = realmManager.createRealm("JUGGLER");
|
realmModel = realmManager.createRealm("JUGGLER");
|
||||||
|
@ -79,7 +74,6 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
||||||
realmModel.addDefaultRole("foo");
|
realmModel.addDefaultRole("foo");
|
||||||
|
|
||||||
System.out.println(realmModel.getId());
|
|
||||||
realmModel = realmManager.getRealm(realmModel.getId());
|
realmModel = realmManager.getRealm(realmModel.getId());
|
||||||
Assert.assertNotNull(realmModel);
|
Assert.assertNotNull(realmModel);
|
||||||
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
||||||
|
@ -93,13 +87,11 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
||||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
||||||
|
|
||||||
String id = realmModel.getId();
|
realmModel.getId();
|
||||||
System.out.println("id: " + id);
|
|
||||||
|
|
||||||
commit();
|
commit();
|
||||||
List<RealmModel> realms = identitySession.getRealms(null);
|
List<RealmModel> realms = identitySession.getRealms();
|
||||||
System.out.println("num realms: " + realms.size());
|
Assert.assertEquals(realms.size(), 2);
|
||||||
Assert.assertEquals(realms.size(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.junit.Assert;
|
||||||
import org.junit.FixMethodOrder;
|
import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.keycloak.models.AccountRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -56,7 +57,7 @@ public class ImportTest extends AbstractModelTest {
|
||||||
// Test applications imported
|
// Test applications imported
|
||||||
ApplicationModel application = realm.getApplicationByName("Application");
|
ApplicationModel application = realm.getApplicationByName("Application");
|
||||||
ApplicationModel otherApp = realm.getApplicationByName("OtherApp");
|
ApplicationModel otherApp = realm.getApplicationByName("OtherApp");
|
||||||
ApplicationModel accountApp = realm.getApplicationByName(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountApp = realm.getApplicationByName(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
ApplicationModel nonExisting = realm.getApplicationByName("NonExisting");
|
ApplicationModel nonExisting = realm.getApplicationByName("NonExisting");
|
||||||
Assert.assertNotNull(application);
|
Assert.assertNotNull(application);
|
||||||
Assert.assertNotNull(otherApp);
|
Assert.assertNotNull(otherApp);
|
||||||
|
@ -80,8 +81,8 @@ public class ImportTest extends AbstractModelTest {
|
||||||
Assert.assertTrue(allRoles.contains(realm.getRole("admin")));
|
Assert.assertTrue(allRoles.contains(realm.getRole("admin")));
|
||||||
Assert.assertTrue(allRoles.contains(application.getRole("app-admin")));
|
Assert.assertTrue(allRoles.contains(application.getRole("app-admin")));
|
||||||
Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-admin")));
|
Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-admin")));
|
||||||
Assert.assertTrue(allRoles.contains(accountApp.getRole(Constants.ACCOUNT_PROFILE_ROLE)));
|
Assert.assertTrue(allRoles.contains(accountApp.getRole(AccountRoles.VIEW_PROFILE)));
|
||||||
Assert.assertTrue(allRoles.contains(accountApp.getRole(Constants.ACCOUNT_MANAGE_ROLE)));
|
Assert.assertTrue(allRoles.contains(accountApp.getRole(AccountRoles.MANAGE_ACCOUNT)));
|
||||||
|
|
||||||
UserModel wburke = realm.getUser("wburke");
|
UserModel wburke = realm.getUser("wburke");
|
||||||
allRoles = realm.getRoleMappings(wburke);
|
allRoles = realm.getRoleMappings(wburke);
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.logging.Logger;
|
||||||
|
import org.jboss.resteasy.spi.HttpResponse;
|
||||||
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
|
import org.keycloak.RSATokenVerifier;
|
||||||
|
import org.keycloak.VerificationException;
|
||||||
|
import org.keycloak.jose.jws.JWSBuilder;
|
||||||
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
|
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
|
||||||
|
import javax.ws.rs.BadRequestException;
|
||||||
|
import javax.ws.rs.NotAuthorizedException;
|
||||||
|
import javax.ws.rs.core.Cookie;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.NewCookie;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class AppAuthManager extends AuthenticationManager {
|
||||||
|
protected static Logger logger = Logger.getLogger(AuthenticationManager.class);
|
||||||
|
|
||||||
|
private String cookieName;
|
||||||
|
private TokenManager tokenManager;
|
||||||
|
|
||||||
|
public AppAuthManager(String cookieName, TokenManager tokenManager) {
|
||||||
|
this.cookieName = cookieName;
|
||||||
|
this.tokenManager = tokenManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NewCookie createCookie(RealmModel realm, UserModel client, String code, URI uri) {
|
||||||
|
JWSInput input = new JWSInput(code);
|
||||||
|
boolean verifiedCode = false;
|
||||||
|
try {
|
||||||
|
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
logger.debug("Failed to verify signature", ignored);
|
||||||
|
}
|
||||||
|
if (!verifiedCode) {
|
||||||
|
logger.debug("unverified access code");
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
String key = input.readContentAsString();
|
||||||
|
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
|
||||||
|
if (accessCode == null) {
|
||||||
|
logger.debug("bad access code");
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
if (accessCode.isExpired()) {
|
||||||
|
logger.debug("access code expired");
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
if (!accessCode.getToken().isActive()) {
|
||||||
|
logger.debug("access token expired");
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
if (!accessCode.getRealm().getId().equals(realm.getId())) {
|
||||||
|
logger.debug("bad realm");
|
||||||
|
throw new BadRequestException();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
|
||||||
|
logger.debug("bad client");
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createLoginCookie(realm, accessCode.getUser(), accessCode.getClient(), cookieName, uri.getRawPath(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NewCookie createRefreshCookie(RealmModel realm, UserModel user, UserModel client, URI uri) {
|
||||||
|
return createLoginCookie(realm, user, client, cookieName, uri.getRawPath(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expireCookie(URI uri) {
|
||||||
|
expireCookie(cookieName, uri.getRawPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auth authenticateCookie(RealmModel realm, HttpHeaders headers) {
|
||||||
|
return authenticateCookie(realm, headers, cookieName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auth authenticate(RealmModel realm, HttpHeaders headers) {
|
||||||
|
Auth auth = authenticateCookie(realm, headers);
|
||||||
|
if (auth != null) return auth;
|
||||||
|
return authenticateBearerToken(realm, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Auth authenticateCookie(RealmModel realm, HttpHeaders headers, String cookieName, boolean checkActive) {
|
||||||
|
logger.info("authenticateCookie");
|
||||||
|
Cookie cookie = headers.getCookies().get(cookieName);
|
||||||
|
if (cookie == null) {
|
||||||
|
logger.info("authenticateCookie could not find cookie: {0}", cookieName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String tokenString = cookie.getValue();
|
||||||
|
try {
|
||||||
|
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName(), checkActive);
|
||||||
|
logger.info("token verified");
|
||||||
|
if (checkActive && !token.isActive()) {
|
||||||
|
logger.info("cookie expired");
|
||||||
|
expireCookie(cookie.getName(), cookie.getPath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel user = realm.getUserById(token.getSubject());
|
||||||
|
if (user == null || !user.isEnabled()) {
|
||||||
|
logger.info("Unknown user in cookie");
|
||||||
|
expireCookie(cookie.getName(), cookie.getPath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel client = null;
|
||||||
|
if (token.getIssuedFor() != null) {
|
||||||
|
client = realm.getUser(token.getIssuedFor());
|
||||||
|
if (client == null || !client.isEnabled()) {
|
||||||
|
logger.info("Unknown client in cookie");
|
||||||
|
expireCookie(cookie.getName(), cookie.getPath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Auth(realm, user, client);
|
||||||
|
} catch (VerificationException e) {
|
||||||
|
logger.info("Failed to verify cookie", e);
|
||||||
|
expireCookie(cookie.getName(), cookie.getPath());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Auth authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
|
||||||
|
String tokenString;
|
||||||
|
String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (authHeader == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
String[] split = authHeader.trim().split("\\s+");
|
||||||
|
if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
|
||||||
|
if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
|
||||||
|
tokenString = split[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName());
|
||||||
|
if (!token.isActive()) {
|
||||||
|
throw new NotAuthorizedException("token_expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel user = realm.getUserById(token.getSubject());
|
||||||
|
if (user == null || !user.isEnabled()) {
|
||||||
|
throw new NotAuthorizedException("invalid_user");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel client = null;
|
||||||
|
if (token.getIssuedFor() != null) {
|
||||||
|
client = realm.getUser(token.getIssuedFor());
|
||||||
|
if (client == null || !client.isEnabled()) {
|
||||||
|
throw new NotAuthorizedException("invalid_user");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Auth(token, user, client);
|
||||||
|
} catch (VerificationException e) {
|
||||||
|
logger.error("Failed to verify token", e);
|
||||||
|
throw new NotAuthorizedException("invalid_token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.services.managers;
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -62,7 +63,9 @@ public class ApplianceBootstrap {
|
||||||
adminConsole.setBaseUrl("/auth/admin/index.html");
|
adminConsole.setBaseUrl("/auth/admin/index.html");
|
||||||
adminConsole.setEnabled(true);
|
adminConsole.setEnabled(true);
|
||||||
|
|
||||||
RoleModel adminRole = adminConsole.addRole(Constants.ADMIN_CONSOLE_ADMIN_ROLE);
|
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||||
|
|
||||||
|
adminConsole.addScope(adminRole);
|
||||||
|
|
||||||
UserModel adminUser = realm.addUser("admin");
|
UserModel adminUser = realm.addUser("admin");
|
||||||
adminUser.setEnabled(true);
|
adminUser.setEnabled(true);
|
||||||
|
@ -74,7 +77,7 @@ public class ApplianceBootstrap {
|
||||||
|
|
||||||
realm.grantRole(adminUser, adminRole);
|
realm.grantRole(adminUser, adminRole);
|
||||||
|
|
||||||
ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
for (String r : accountApp.getDefaultRoles()) {
|
for (String r : accountApp.getDefaultRoles()) {
|
||||||
realm.grantRole(adminUser, accountApp.getRole(r));
|
realm.grantRole(adminUser, accountApp.getRole(r));
|
||||||
}
|
}
|
||||||
|
|
138
services/src/main/java/org/keycloak/services/managers/Auth.java
Normal file
138
services/src/main/java/org/keycloak/services/managers/Auth.java
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
|
||||||
|
import javax.ws.rs.ForbiddenException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Auth {
|
||||||
|
private final boolean cookie;
|
||||||
|
private final RealmModel realm;
|
||||||
|
private final AccessToken token;
|
||||||
|
private final UserModel user;
|
||||||
|
private final UserModel client;
|
||||||
|
|
||||||
|
public Auth(RealmModel realm, UserModel user, UserModel client) {
|
||||||
|
this.cookie = true;
|
||||||
|
this.realm = realm;
|
||||||
|
this.token = null;
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auth(AccessToken token, UserModel user, UserModel client) {
|
||||||
|
this.cookie = false;
|
||||||
|
this.token = token;
|
||||||
|
this.realm = null;
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCookie() {
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmModel getRealm() {
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserModel getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserModel getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void require(String role) {
|
||||||
|
if (!has(role)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void require(String app, String role) {
|
||||||
|
if (!has(app, role)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void require(ApplicationModel app, String role) {
|
||||||
|
if (!has(app, role)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requireOneOf(String app, String... roles) {
|
||||||
|
if(!hasOneOf(app, roles)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requireOneOf(ApplicationModel app, String... roles) {
|
||||||
|
if(!hasOneOf(app, roles)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(String role) {
|
||||||
|
if (cookie) {
|
||||||
|
return realm.hasRole(user, realm.getRole(role));
|
||||||
|
} else {
|
||||||
|
return token.getRealmAccess() != null && token.getRealmAccess().isUserInRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(String app, String role) {
|
||||||
|
if (cookie) {
|
||||||
|
return realm.hasRole(user, realm.getApplicationByName(app).getRole(role));
|
||||||
|
} else {
|
||||||
|
AccessToken.Access access = token.getResourceAccess(app);
|
||||||
|
return access != null && access.isUserInRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(ApplicationModel app, String role) {
|
||||||
|
if (cookie) {
|
||||||
|
return realm.hasRole(user, app.getRole(role));
|
||||||
|
} else {
|
||||||
|
AccessToken.Access access = token.getResourceAccess(app.getName());
|
||||||
|
return access != null && access.isUserInRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasOneOf(String app, String... roles) {
|
||||||
|
for (String r : roles) {
|
||||||
|
if (has(app, r)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasOneOf(ApplicationModel app, String... roles) {
|
||||||
|
for (String r : roles) {
|
||||||
|
if (has(app, r)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,8 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.services.resources.AccountService;
|
|
||||||
import org.keycloak.services.resources.admin.AdminService;
|
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
|
||||||
import javax.ws.rs.NotAuthorizedException;
|
|
||||||
import javax.ws.rs.core.Cookie;
|
import javax.ws.rs.core.Cookie;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
@ -59,19 +56,6 @@ public class AuthenticationManager {
|
||||||
return createLoginCookie(realm, user, null, cookieName, cookiePath, rememberMe);
|
return createLoginCookie(realm, user, null, cookieName, cookiePath, rememberMe);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NewCookie createSaasIdentityCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
|
|
||||||
String cookieName = AdminService.SAAS_IDENTITY_COOKIE;
|
|
||||||
URI uri = AdminService.saasCookiePath(uriInfo).build();
|
|
||||||
String cookiePath = uri.getRawPath();
|
|
||||||
return createLoginCookie(realm, user, null, cookieName, cookiePath, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NewCookie createAccountIdentityCookie(RealmModel realm, UserModel user, UserModel client, URI uri) {
|
|
||||||
String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
|
|
||||||
String cookiePath = uri.getRawPath();
|
|
||||||
return createLoginCookie(realm, user, client, cookieName, cookiePath, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected NewCookie createLoginCookie(RealmModel realm, UserModel user, UserModel client, String cookieName, String cookiePath, boolean rememberMe) {
|
protected NewCookie createLoginCookie(RealmModel realm, UserModel user, UserModel client, String cookieName, String cookiePath, boolean rememberMe) {
|
||||||
AccessToken identityToken = createIdentityToken(realm, user);
|
AccessToken identityToken = createIdentityToken(realm, user);
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
|
@ -104,7 +88,6 @@ public class AuthenticationManager {
|
||||||
return encodedToken;
|
return encodedToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
|
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
|
||||||
logger.debug("Expiring identity cookie");
|
logger.debug("Expiring identity cookie");
|
||||||
String path = getIdentityCookiePath(realm, uriInfo);
|
String path = getIdentityCookiePath(realm, uriInfo);
|
||||||
|
@ -123,17 +106,6 @@ public class AuthenticationManager {
|
||||||
return uri.getRawPath();
|
return uri.getRawPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expireSaasIdentityCookie(UriInfo uriInfo) {
|
|
||||||
URI uri = AdminService.saasCookiePath(uriInfo).build();
|
|
||||||
String cookiePath = uri.getRawPath();
|
|
||||||
expireCookie(AdminService.SAAS_IDENTITY_COOKIE, cookiePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void expireAccountIdentityCookie(URI uri) {
|
|
||||||
String cookiePath = uri.getRawPath();
|
|
||||||
expireCookie(AccountService.ACCOUNT_IDENTITY_COOKIE, cookiePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void expireCookie(String cookieName, String path) {
|
public void expireCookie(String cookieName, String path) {
|
||||||
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
|
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
|
@ -149,42 +121,13 @@ public class AuthenticationManager {
|
||||||
return authenticateIdentityCookie(realm, uriInfo, headers, true);
|
return authenticateIdentityCookie(realm, uriInfo, headers, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, boolean checkActive) {
|
public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, boolean checkActive) {
|
||||||
logger.info("authenticateIdentityCookie");
|
logger.info("authenticateIdentityCookie");
|
||||||
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
||||||
Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName, checkActive);
|
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName, checkActive);
|
||||||
return auth != null ? auth.getUser() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserModel authenticateSaasIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName, boolean checkActive) {
|
||||||
String cookieName = AdminService.SAAS_IDENTITY_COOKIE;
|
|
||||||
Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName, true);
|
|
||||||
return auth != null ? auth.getUser() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auth authenticateAccountIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
|
||||||
String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
|
|
||||||
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserModel authenticateSaasIdentity(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
|
||||||
UserModel user = authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
|
||||||
if (user != null) return user;
|
|
||||||
|
|
||||||
Auth auth = authenticateBearerToken(realm, headers);
|
|
||||||
return auth != null ? auth.getUser() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auth authenticateAccountIdentity(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
|
||||||
Auth auth = authenticateAccountIdentityCookie(realm, uriInfo, headers);
|
|
||||||
if (auth != null) return auth;
|
|
||||||
|
|
||||||
return authenticateBearerToken(realm, headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected Auth authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName, boolean checkActive) {
|
|
||||||
logger.info("authenticateIdentityCookie");
|
logger.info("authenticateIdentityCookie");
|
||||||
Cookie cookie = headers.getCookies().get(cookieName);
|
Cookie cookie = headers.getCookies().get(cookieName);
|
||||||
if (cookie == null) {
|
if (cookie == null) {
|
||||||
|
@ -202,27 +145,14 @@ public class AuthenticationManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth auth = new Auth(token);
|
|
||||||
|
|
||||||
UserModel user = realm.getUserById(token.getSubject());
|
UserModel user = realm.getUserById(token.getSubject());
|
||||||
if (user == null || !user.isEnabled()) {
|
if (user == null || !user.isEnabled()) {
|
||||||
logger.info("Unknown user in identity cookie");
|
logger.info("Unknown user in identity cookie");
|
||||||
expireIdentityCookie(realm, uriInfo);
|
expireIdentityCookie(realm, uriInfo);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
auth.setUser(user);
|
|
||||||
|
|
||||||
if (token.getIssuedFor() != null) {
|
return user;
|
||||||
UserModel client = realm.getUser(token.getIssuedFor());
|
|
||||||
if (client == null || !client.isEnabled()) {
|
|
||||||
logger.info("Unknown client in identity cookie");
|
|
||||||
expireIdentityCookie(realm, uriInfo);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
auth.setClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth;
|
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
logger.info("Failed to verify identity cookie", e);
|
logger.info("Failed to verify identity cookie", e);
|
||||||
expireCookie(cookie.getName(), cookie.getPath());
|
expireCookie(cookie.getName(), cookie.getPath());
|
||||||
|
@ -230,49 +160,6 @@ public class AuthenticationManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Auth authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
|
|
||||||
String tokenString = null;
|
|
||||||
String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
|
|
||||||
if (authHeader == null) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
String[] split = authHeader.trim().split("\\s+");
|
|
||||||
if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
|
|
||||||
if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
|
|
||||||
tokenString = split[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName());
|
|
||||||
if (!token.isActive()) {
|
|
||||||
throw new NotAuthorizedException("token_expired");
|
|
||||||
}
|
|
||||||
|
|
||||||
Auth auth = new Auth(token);
|
|
||||||
|
|
||||||
UserModel user = realm.getUserById(token.getSubject());
|
|
||||||
if (user == null || !user.isEnabled()) {
|
|
||||||
throw new NotAuthorizedException("invalid_user");
|
|
||||||
}
|
|
||||||
auth.setUser(user);
|
|
||||||
|
|
||||||
if (token.getIssuedFor() != null) {
|
|
||||||
UserModel client = realm.getUser(token.getIssuedFor());
|
|
||||||
if (client == null || !client.isEnabled()) {
|
|
||||||
throw new NotAuthorizedException("invalid_user");
|
|
||||||
}
|
|
||||||
auth.setClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth;
|
|
||||||
} catch (VerificationException e) {
|
|
||||||
logger.error("Failed to verify token", e);
|
|
||||||
throw new NotAuthorizedException("invalid_token");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public AuthenticationStatus authenticateForm(RealmModel realm, UserModel user, MultivaluedMap<String, String> formData) {
|
public AuthenticationStatus authenticateForm(RealmModel realm, UserModel user, MultivaluedMap<String, String> formData) {
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
logger.debug("Not Authenticated! Incorrect user name");
|
logger.debug("Not Authenticated! Incorrect user name");
|
||||||
|
@ -356,34 +243,4 @@ public class AuthenticationManager {
|
||||||
SUCCESS, ACCOUNT_DISABLED, ACTIONS_REQUIRED, INVALID_USER, INVALID_CREDENTIALS, MISSING_PASSWORD, MISSING_TOTP, FAILED
|
SUCCESS, ACCOUNT_DISABLED, ACTIONS_REQUIRED, INVALID_USER, INVALID_CREDENTIALS, MISSING_PASSWORD, MISSING_TOTP, FAILED
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Auth {
|
|
||||||
private AccessToken token;
|
|
||||||
private UserModel user;
|
|
||||||
private UserModel client;
|
|
||||||
|
|
||||||
public Auth(AccessToken token) {
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccessToken getToken() {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserModel getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserModel getClient() {
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUser(UserModel user) {
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setClient(UserModel client) {
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class ModelToRepresentation {
|
||||||
rep.setPasswordPolicy(realm.getPasswordPolicy().toString());
|
rep.setPasswordPolicy(realm.getPasswordPolicy().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
|
|
||||||
List<String> defaultRoles = realm.getDefaultRoles();
|
List<String> defaultRoles = realm.getDefaultRoles();
|
||||||
if (!defaultRoles.isEmpty()) {
|
if (!defaultRoles.isEmpty()) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package org.keycloak.services.managers;
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
|
import org.keycloak.models.AccountRoles;
|
||||||
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -59,7 +61,6 @@ public class RealmManager {
|
||||||
return identitySession.getRealmByName(name);
|
return identitySession.getRealmByName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public RealmModel createRealm(String name) {
|
public RealmModel createRealm(String name) {
|
||||||
return createRealm(name, name);
|
return createRealm(name, name);
|
||||||
}
|
}
|
||||||
|
@ -71,13 +72,31 @@ public class RealmManager {
|
||||||
realm.addRole(Constants.APPLICATION_ROLE);
|
realm.addRole(Constants.APPLICATION_ROLE);
|
||||||
realm.addRole(Constants.IDENTITY_REQUESTER_ROLE);
|
realm.addRole(Constants.IDENTITY_REQUESTER_ROLE);
|
||||||
|
|
||||||
|
setupAdminManagement(realm);
|
||||||
setupAccountManagement(realm);
|
setupAccountManagement(realm);
|
||||||
|
|
||||||
realm.addRequiredOAuthClientCredential(UserCredentialModel.SECRET);
|
realm.addRequiredOAuthClientCredential(UserCredentialModel.SECRET);
|
||||||
realm.addRequiredResourceCredential(UserCredentialModel.SECRET);
|
realm.addRequiredResourceCredential(UserCredentialModel.SECRET);
|
||||||
|
|
||||||
return realm;
|
return realm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean removeRealm(RealmModel realm) {
|
||||||
|
boolean removed = identitySession.removeRealm(realm.getId());
|
||||||
|
|
||||||
|
RealmModel adminRealm = getKeycloakAdminstrationRealm();
|
||||||
|
RoleModel adminRole = adminRealm.getRole(AdminRoles.ADMIN);
|
||||||
|
|
||||||
|
ApplicationModel realmAdminApp = adminRealm.getApplicationByName(AdminRoles.getAdminApp(realm));
|
||||||
|
for (RoleModel r : realmAdminApp.getRoles()) {
|
||||||
|
adminRole.removeCompositeRole(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
adminRealm.removeApplication(realmAdminApp.getId());
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
public void generateRealmKeys(RealmModel realm) {
|
public void generateRealmKeys(RealmModel realm) {
|
||||||
KeyPair keyPair = null;
|
KeyPair keyPair = null;
|
||||||
try {
|
try {
|
||||||
|
@ -134,19 +153,41 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupAdminManagement(RealmModel realm) {
|
||||||
|
RealmModel adminRealm;
|
||||||
|
RoleModel adminRole;
|
||||||
|
|
||||||
|
if (realm.getName().equals(Constants.ADMIN_REALM)) {
|
||||||
|
adminRealm = realm;
|
||||||
|
|
||||||
|
adminRole = realm.addRole(AdminRoles.ADMIN);
|
||||||
|
} else {
|
||||||
|
adminRealm = identitySession.getRealmByName(Constants.ADMIN_REALM);
|
||||||
|
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession));
|
||||||
|
ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, AdminRoles.getAdminApp(realm));
|
||||||
|
|
||||||
|
for (String r : AdminRoles.ALL_REALM_ROLES) {
|
||||||
|
RoleModel role = realmAdminApp.addRole(r);
|
||||||
|
adminRole.addCompositeRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupAccountManagement(RealmModel realm) {
|
private void setupAccountManagement(RealmModel realm) {
|
||||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
if (application == null) {
|
if (application == null) {
|
||||||
application = new ApplicationManager(this).createApplication(realm, Constants.ACCOUNT_APPLICATION);
|
application = new ApplicationManager(this).createApplication(realm, Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
application.setEnabled(true);
|
application.setEnabled(true);
|
||||||
|
|
||||||
application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE);
|
for (String role : AccountRoles.ALL) {
|
||||||
application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE);
|
application.addDefaultRole(role);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RealmModel importRealm(RealmRepresentation rep, UserModel realmCreator) {
|
public RealmModel importRealm(RealmRepresentation rep) {
|
||||||
String id = rep.getId();
|
String id = rep.getId();
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
id = KeycloakModelUtils.generateId();
|
id = KeycloakModelUtils.generateId();
|
||||||
|
@ -299,7 +340,6 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (rep.getRoleMappings() != null) {
|
if (rep.getRoleMappings() != null) {
|
||||||
for (UserRoleMappingRepresentation mapping : rep.getRoleMappings()) {
|
for (UserRoleMappingRepresentation mapping : rep.getRoleMappings()) {
|
||||||
UserModel user = userMap.get(mapping.getUsername());
|
UserModel user = userMap.get(mapping.getUsername());
|
||||||
|
|
|
@ -23,7 +23,6 @@ package org.keycloak.services.resources;
|
||||||
|
|
||||||
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.AbstractOAuthClient;
|
|
||||||
import org.keycloak.account.Account;
|
import org.keycloak.account.Account;
|
||||||
import org.keycloak.account.AccountLoader;
|
import org.keycloak.account.AccountLoader;
|
||||||
import org.keycloak.account.AccountPages;
|
import org.keycloak.account.AccountPages;
|
||||||
|
@ -32,10 +31,10 @@ import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||||
import org.keycloak.models.*;
|
import org.keycloak.models.*;
|
||||||
import org.keycloak.models.utils.TimeBasedOTP;
|
import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
import org.keycloak.representations.AccessToken;
|
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.services.managers.AccessCodeEntry;
|
import org.keycloak.services.managers.AccessCodeEntry;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
|
import org.keycloak.services.managers.Auth;
|
||||||
import org.keycloak.services.managers.ModelToRepresentation;
|
import org.keycloak.services.managers.ModelToRepresentation;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
import org.keycloak.services.managers.TokenManager;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
|
@ -68,23 +67,23 @@ public class AccountService {
|
||||||
@Context
|
@Context
|
||||||
private UriInfo uriInfo;
|
private UriInfo uriInfo;
|
||||||
|
|
||||||
private AuthenticationManager authManager = new AuthenticationManager();
|
private AppAuthManager authManager;
|
||||||
|
|
||||||
private ApplicationModel application;
|
private ApplicationModel application;
|
||||||
|
|
||||||
private TokenManager tokenManager;
|
|
||||||
|
|
||||||
public AccountService(RealmModel realm, ApplicationModel application, TokenManager tokenManager) {
|
public AccountService(RealmModel realm, ApplicationModel application, TokenManager tokenManager) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.tokenManager = tokenManager;
|
this.authManager = new AppAuthManager("KEYCLOAK_ACCOUNT_IDENTITY", tokenManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response forwardToPage(String path, AccountPages page) {
|
private Response forwardToPage(String path, AccountPages page) {
|
||||||
AuthenticationManager.Auth auth = getAuth(false);
|
Auth auth = getAuth(false);
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
if (!hasAccess(auth)) {
|
try {
|
||||||
return noAccess();
|
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||||
|
} catch (ForbiddenException e) {
|
||||||
|
return Flows.forms(realm, request, uriInfo).setError("No access").createErrorPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
Account account = AccountLoader.load().createAccount(uriInfo).setRealm(realm).setUser(auth.getUser());
|
Account account = AccountLoader.load().createAccount(uriInfo).setRealm(realm).setUser(auth.getUser());
|
||||||
|
@ -100,10 +99,6 @@ public class AccountService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response noAccess() {
|
|
||||||
return Flows.forms(realm, request, uriInfo).setError("No access").createErrorPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@OPTIONS
|
@OPTIONS
|
||||||
public Response accountPreflight() {
|
public Response accountPreflight() {
|
||||||
|
@ -117,10 +112,9 @@ public class AccountService {
|
||||||
if (types.contains(MediaType.WILDCARD_TYPE) || (types.contains(MediaType.TEXT_HTML_TYPE))) {
|
if (types.contains(MediaType.WILDCARD_TYPE) || (types.contains(MediaType.TEXT_HTML_TYPE))) {
|
||||||
return forwardToPage(null, AccountPages.ACCOUNT);
|
return forwardToPage(null, AccountPages.ACCOUNT);
|
||||||
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) {
|
auth.requireOneOf(application, AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
|
||||||
return Response.status(Response.Status.FORBIDDEN).build();
|
|
||||||
}
|
|
||||||
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
|
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
|
||||||
} else {
|
} else {
|
||||||
return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
|
return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
|
||||||
|
@ -143,10 +137,8 @@ public class AccountService {
|
||||||
@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) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth)) {
|
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||||
return noAccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
|
@ -167,10 +159,8 @@ public class AccountService {
|
||||||
@Path("totp-remove")
|
@Path("totp-remove")
|
||||||
@GET
|
@GET
|
||||||
public Response processTotpRemove() {
|
public Response processTotpRemove() {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth)) {
|
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||||
return noAccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
user.setTotp(false);
|
user.setTotp(false);
|
||||||
|
@ -183,10 +173,8 @@ public class AccountService {
|
||||||
@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) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth)) {
|
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||||
return noAccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
|
@ -215,10 +203,8 @@ public class AccountService {
|
||||||
@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) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth)) {
|
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||||
return noAccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
|
@ -285,61 +271,25 @@ public class AccountService {
|
||||||
throw new BadRequestException();
|
throw new BadRequestException();
|
||||||
}
|
}
|
||||||
|
|
||||||
JWSInput input = new JWSInput(code);
|
|
||||||
boolean verifiedCode = false;
|
|
||||||
try {
|
|
||||||
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
logger.debug("Failed to verify signature", ignored);
|
|
||||||
}
|
|
||||||
if (!verifiedCode) {
|
|
||||||
logger.debug("unverified access code");
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
String key = input.readContentAsString();
|
|
||||||
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
|
|
||||||
if (accessCode == null) {
|
|
||||||
logger.debug("bad access code");
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
if (accessCode.isExpired()) {
|
|
||||||
logger.debug("access code expired");
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
if (!accessCode.getToken().isActive()) {
|
|
||||||
logger.debug("access token expired");
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
if (!accessCode.getRealm().getId().equals(realm.getId())) {
|
|
||||||
logger.debug("bad realm");
|
|
||||||
throw new BadRequestException();
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
|
|
||||||
logger.debug("bad client");
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
|
|
||||||
URI accountUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName());
|
URI accountUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName());
|
||||||
URI redirectUri = path != null ? accountUri.resolve(path) : accountUri;
|
URI redirectUri = path != null ? accountUri.resolve(path) : accountUri;
|
||||||
if (referrer != null) {
|
if (referrer != null) {
|
||||||
redirectUri = redirectUri.resolve("?referrer=" + referrer);
|
redirectUri = redirectUri.resolve("?referrer=" + referrer);
|
||||||
}
|
}
|
||||||
|
|
||||||
NewCookie cookie = authManager.createAccountIdentityCookie(realm, accessCode.getUser(), client, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
|
NewCookie cookie = authManager.createCookie(realm, client, code, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
|
||||||
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
||||||
} finally {
|
} finally {
|
||||||
authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getRawPath());
|
authManager.expireCookie(Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("logout")
|
@Path("logout")
|
||||||
@GET
|
@GET
|
||||||
public Response logout() {
|
public Response logout() {
|
||||||
// TODO Should use single-sign out via TokenService
|
|
||||||
URI baseUri = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
|
URI baseUri = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
|
||||||
authManager.expireIdentityCookie(realm, uriInfo);
|
authManager.expireIdentityCookie(realm, uriInfo);
|
||||||
authManager.expireAccountIdentityCookie(baseUri);
|
authManager.expireCookie(baseUri);
|
||||||
return Response.status(302).location(baseUri).build();
|
return Response.status(302).location(baseUri).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +298,7 @@ public class AccountService {
|
||||||
String authUrl = Urls.realmLoginPage(uriInfo.getBaseUri(), realm.getName()).toString();
|
String authUrl = Urls.realmLoginPage(uriInfo.getBaseUri(), realm.getName()).toString();
|
||||||
oauth.setAuthUrl(authUrl);
|
oauth.setAuthUrl(authUrl);
|
||||||
|
|
||||||
oauth.setClientId(Constants.ACCOUNT_APPLICATION);
|
oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
|
|
||||||
UriBuilder uriBuilder = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect");
|
UriBuilder uriBuilder = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect");
|
||||||
|
|
||||||
|
@ -368,42 +318,14 @@ public class AccountService {
|
||||||
return oauth.redirect(uriInfo, accountUri.toString());
|
return oauth.redirect(uriInfo, accountUri.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthenticationManager.Auth getAuth(boolean error) {
|
private Auth getAuth(boolean error) {
|
||||||
AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers);
|
Auth auth = authManager.authenticate(realm, headers);
|
||||||
if (auth == null && error) {
|
if (auth == null && error) {
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAccess(AuthenticationManager.Auth auth) {
|
|
||||||
return hasAccess(auth, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasAccess(AuthenticationManager.Auth auth, String role) {
|
|
||||||
UserModel client = auth.getClient();
|
|
||||||
if (realm.hasRole(client, realm.getRole(Constants.APPLICATION_ROLE))) {
|
|
||||||
// Tokens from cookies don't have roles
|
|
||||||
UserModel user = auth.getUser();
|
|
||||||
if (hasRole(user, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(user, role))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessToken.Access access = auth.getToken().getResourceAccess(application.getName());
|
|
||||||
if (access != null) {
|
|
||||||
if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE) || (role != null && access.isUserInRole(role))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasRole(UserModel user, String role) {
|
|
||||||
return realm.hasRole(user, application.getRole(role));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getReferrer() {
|
private String getReferrer() {
|
||||||
String referrer = uriInfo.getQueryParameters().getFirst("referrer");
|
String referrer = uriInfo.getQueryParameters().getFirst("referrer");
|
||||||
if (referrer != null) {
|
if (referrer != null) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class RealmsResource {
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel realm = locateRealm(name, realmManager);
|
RealmModel realm = locateRealm(name, realmManager);
|
||||||
|
|
||||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
if (application == null || !application.isEnabled()) {
|
if (application == null || !application.isEnabled()) {
|
||||||
logger.debug("account management not enabled");
|
logger.debug("account management not enabled");
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
|
|
@ -1,49 +1,44 @@
|
||||||
package org.keycloak.services.resources.admin;
|
package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonProperty;
|
||||||
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.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
import org.jboss.resteasy.spi.HttpResponse;
|
import org.jboss.resteasy.spi.HttpResponse;
|
||||||
import org.jboss.resteasy.spi.NotImplementedYetException;
|
|
||||||
import org.keycloak.AbstractOAuthClient;
|
|
||||||
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.services.managers.AccessCodeEntry;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.Auth;
|
||||||
import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
|
|
||||||
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.resources.TokenService;
|
import org.keycloak.services.resources.TokenService;
|
||||||
import org.keycloak.services.resources.flows.Flows;
|
import org.keycloak.services.resources.flows.Flows;
|
||||||
import org.keycloak.services.resources.flows.OAuthFlows;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.NotAuthorizedException;
|
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.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
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.MultivaluedMap;
|
|
||||||
import javax.ws.rs.core.NewCookie;
|
import javax.ws.rs.core.NewCookie;
|
||||||
import javax.ws.rs.core.Response;
|
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;
|
||||||
import javax.ws.rs.ext.Providers;
|
import javax.ws.rs.ext.Providers;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -52,8 +47,6 @@ import java.net.URI;
|
||||||
@Path("/admin")
|
@Path("/admin")
|
||||||
public class AdminService {
|
public class AdminService {
|
||||||
protected static final Logger logger = Logger.getLogger(AdminService.class);
|
protected static final Logger logger = Logger.getLogger(AdminService.class);
|
||||||
public static final String REALM_CREATOR_ROLE = "realm-creator";
|
|
||||||
public static final String SAAS_IDENTITY_COOKIE = "KEYCLOAK_SAAS_IDENTITY";
|
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
protected UriInfo uriInfo;
|
protected UriInfo uriInfo;
|
||||||
|
@ -73,25 +66,32 @@ public class AdminService {
|
||||||
@Context
|
@Context
|
||||||
protected Providers providers;
|
protected Providers providers;
|
||||||
|
|
||||||
|
|
||||||
protected String adminPath = "/admin/index.html";
|
protected String adminPath = "/admin/index.html";
|
||||||
protected AuthenticationManager authManager = new AuthenticationManager();
|
protected AppAuthManager authManager;
|
||||||
protected TokenManager tokenManager;
|
protected TokenManager tokenManager;
|
||||||
|
|
||||||
public AdminService(TokenManager tokenManager) {
|
public AdminService(TokenManager tokenManager) {
|
||||||
this.tokenManager = tokenManager;
|
this.tokenManager = tokenManager;
|
||||||
|
this.authManager = new AppAuthManager("KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WhoAmI {
|
public static class WhoAmI {
|
||||||
protected String userId;
|
protected String userId;
|
||||||
protected String displayName;
|
protected String displayName;
|
||||||
|
|
||||||
|
@JsonProperty("admin")
|
||||||
|
protected boolean admin;
|
||||||
|
@JsonProperty("realm_access")
|
||||||
|
protected Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
|
||||||
|
|
||||||
public WhoAmI() {
|
public WhoAmI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public WhoAmI(String userId, String displayName) {
|
public WhoAmI(String userId, String displayName, boolean admin, Map<String, Set<String>> realmAccess) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
|
this.admin = admin;
|
||||||
|
this.realmAccess = realmAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
|
@ -109,6 +109,22 @@ public class AdminService {
|
||||||
public void setDisplayName(String displayName) {
|
public void setDisplayName(String displayName) {
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAdmin() {
|
||||||
|
return admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdmin(boolean admin) {
|
||||||
|
this.admin = admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Set<String>> getRealmAccess() {
|
||||||
|
return realmAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealmAccess(Map<String, Set<String>> realmAccess) {
|
||||||
|
this.realmAccess = realmAccess;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("keepalive")
|
@Path("keepalive")
|
||||||
|
@ -120,11 +136,11 @@ public class AdminService {
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||||
if (realm == null)
|
if (realm == null)
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
Auth auth = authManager.authenticateCookie(realm, headers);
|
||||||
if (user == null) {
|
if (auth == null) {
|
||||||
return Response.status(401).build();
|
return Response.status(401).build();
|
||||||
}
|
}
|
||||||
NewCookie refreshCookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
|
NewCookie refreshCookie = authManager.createRefreshCookie(realm, auth.getUser(), auth.getClient(), AdminService.saasCookiePath(uriInfo).build());
|
||||||
return Response.noContent().cookie(refreshCookie).build();
|
return Response.noContent().cookie(refreshCookie).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +153,47 @@ public class AdminService {
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||||
if (realm == null)
|
if (realm == null)
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
Auth auth = authManager.authenticateCookie(realm, headers);
|
||||||
|
UserModel user = auth.getUser();
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return Response.status(401).build();
|
return Response.status(401).build();
|
||||||
}
|
}
|
||||||
// keycloak is bootstrapped with an admin user with no first/last name, so use login name as display name
|
|
||||||
return Response.ok(new WhoAmI(user.getLoginName(), user.getLoginName())).build();
|
String displayName;
|
||||||
|
if (user.getFirstName() != null || user.getLastName() != null) {
|
||||||
|
displayName = user.getFirstName();
|
||||||
|
if (user.getLastName() != null) {
|
||||||
|
displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayName = user.getLoginName();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean admin = realm.hasRole(user, realm.getRole("admin"));
|
||||||
|
|
||||||
|
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
|
||||||
|
addRealmAdminAccess(realmAccess, auth.getRealm().getRoleMappings(auth.getUser()));
|
||||||
|
|
||||||
|
return Response.ok(new WhoAmI(user.getId(), displayName, admin, realmAccess)).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
|
||||||
|
for (RoleModel r : roles) {
|
||||||
|
if (r.getContainer() instanceof ApplicationModel) {
|
||||||
|
ApplicationModel app = (ApplicationModel) r.getContainer();
|
||||||
|
if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) {
|
||||||
|
String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length());
|
||||||
|
if (!realmAdminAccess.containsKey(realm)) {
|
||||||
|
realmAdminAccess.put(realm, new HashSet<String>());
|
||||||
|
}
|
||||||
|
realmAdminAccess.get(realm).add(r.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.isComposite()) {
|
||||||
|
addRealmAdminAccess(realmAdminAccess, r.getComposites());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("isLoggedIn.js")
|
@Path("isLoggedIn.js")
|
||||||
|
@ -157,7 +208,7 @@ public class AdminService {
|
||||||
return "var keycloakCookieLoggedIn = false;";
|
return "var keycloakCookieLoggedIn = false;";
|
||||||
|
|
||||||
}
|
}
|
||||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
UserModel user = authManager.authenticateCookie(realm, headers).getUser();
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return "var keycloakCookieLoggedIn = false;";
|
return "var keycloakCookieLoggedIn = false;";
|
||||||
}
|
}
|
||||||
|
@ -176,23 +227,14 @@ public class AdminService {
|
||||||
@Path("realms")
|
@Path("realms")
|
||||||
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
|
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel saasRealm = getAdminstrationRealm(realmManager);
|
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||||
if (saasRealm == null)
|
if (adminRealm == null)
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
|
Auth auth = authManager.authenticate(adminRealm, headers);
|
||||||
if (admin == null) {
|
if (auth == null) {
|
||||||
throw new NotAuthorizedException("Bearer");
|
throw new NotAuthorizedException("Bearer");
|
||||||
}
|
}
|
||||||
ApplicationModel adminConsole = saasRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
|
||||||
if (adminConsole == null) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
RoleModel adminRole = adminConsole.getRole(Constants.ADMIN_CONSOLE_ADMIN_ROLE);
|
|
||||||
if (!saasRealm.hasRole(admin, adminRole)) {
|
|
||||||
logger.warn("not a Realm admin");
|
|
||||||
throw new NotAuthorizedException("Bearer");
|
|
||||||
}
|
|
||||||
RealmsAdminResource adminResource = new RealmsAdminResource(admin, tokenManager);
|
|
||||||
resourceContext.initResource(adminResource);
|
resourceContext.initResource(adminResource);
|
||||||
return adminResource;
|
return adminResource;
|
||||||
}
|
}
|
||||||
|
@ -200,35 +242,33 @@ public class AdminService {
|
||||||
@Path("serverinfo")
|
@Path("serverinfo")
|
||||||
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
|
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel saasRealm = getAdminstrationRealm(realmManager);
|
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||||
if (saasRealm == null)
|
if (adminRealm == null)
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
|
Auth auth = authManager.authenticate(adminRealm, headers);
|
||||||
|
UserModel admin = auth.getUser();
|
||||||
if (admin == null) {
|
if (admin == null) {
|
||||||
throw new NotAuthorizedException("Bearer");
|
throw new NotAuthorizedException("Bearer");
|
||||||
}
|
}
|
||||||
ApplicationModel adminConsole = saasRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
if (adminConsole == null) {
|
if (adminConsole == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
RoleModel adminRole = adminConsole.getRole(Constants.ADMIN_CONSOLE_ADMIN_ROLE);
|
|
||||||
if (!saasRealm.hasRole(admin, adminRole)) {
|
|
||||||
logger.warn("not a Realm admin");
|
|
||||||
throw new NotAuthorizedException("Bearer");
|
|
||||||
}
|
|
||||||
ServerInfoAdminResource adminResource = new ServerInfoAdminResource();
|
ServerInfoAdminResource adminResource = new ServerInfoAdminResource();
|
||||||
resourceContext.initResource(adminResource);
|
resourceContext.initResource(adminResource);
|
||||||
return adminResource;
|
return adminResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expireCookie() {
|
||||||
|
authManager.expireCookie(AdminService.saasCookiePath(uriInfo).build());
|
||||||
|
}
|
||||||
|
|
||||||
@Path("login")
|
@Path("login")
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
public Response loginPage(@QueryParam("path") String path) {
|
public Response loginPage(@QueryParam("path") String path) {
|
||||||
logger.debug("loginPage ********************** <---");
|
logger.debug("loginPage ********************** <---");
|
||||||
RealmManager realmManager = new RealmManager(session);
|
expireCookie();
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
|
||||||
authManager.expireSaasIdentityCookie(uriInfo);
|
|
||||||
|
|
||||||
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
||||||
String authUrl = TokenService.loginPageUrl(uriInfo).build(Constants.ADMIN_REALM).toString();
|
String authUrl = TokenService.loginPageUrl(uriInfo).build(Constants.ADMIN_REALM).toString();
|
||||||
|
@ -259,7 +299,6 @@ public class AdminService {
|
||||||
URI uri = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "errorOnLoginRedirect").queryParam("error", message).build();
|
URI uri = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "errorOnLoginRedirect").queryParam("error", message).build();
|
||||||
URI logout = TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", uri.toString()).build(Constants.ADMIN_REALM);
|
URI logout = TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", uri.toString()).build(Constants.ADMIN_REALM);
|
||||||
return Response.status(302).location(logout).build();
|
return Response.status(302).location(logout).build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("login-redirect")
|
@Path("login-redirect")
|
||||||
|
@ -279,12 +318,12 @@ public class AdminService {
|
||||||
return redirectOnLoginError(error);
|
return redirectOnLoginError(error);
|
||||||
}
|
}
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||||
if (!realm.isEnabled()) {
|
if (!adminRealm.isEnabled()) {
|
||||||
logger.debug("realm not enabled");
|
logger.debug("realm not enabled");
|
||||||
return redirectOnLoginError("realm not enabled");
|
return redirectOnLoginError("realm not enabled");
|
||||||
}
|
}
|
||||||
ApplicationModel adminConsole = realm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
UserModel adminConsoleUser = adminConsole.getApplicationUser();
|
UserModel adminConsoleUser = adminConsole.getApplicationUser();
|
||||||
if (!adminConsole.isEnabled() || !adminConsoleUser.isEnabled()) {
|
if (!adminConsole.isEnabled() || !adminConsoleUser.isEnabled()) {
|
||||||
logger.debug("admin app not enabled");
|
logger.debug("admin app not enabled");
|
||||||
|
@ -301,47 +340,8 @@ public class AdminService {
|
||||||
}
|
}
|
||||||
new JaxrsOAuthClient().checkStateCookie(uriInfo, headers);
|
new JaxrsOAuthClient().checkStateCookie(uriInfo, headers);
|
||||||
|
|
||||||
JWSInput input = new JWSInput(code);
|
|
||||||
boolean verifiedCode = false;
|
|
||||||
try {
|
|
||||||
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
logger.debug("Failed to verify signature", ignored);
|
|
||||||
}
|
|
||||||
if (!verifiedCode) {
|
|
||||||
logger.debug("unverified access code");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
}
|
|
||||||
String key = input.readContentAsString();
|
|
||||||
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
|
|
||||||
if (accessCode == null) {
|
|
||||||
logger.debug("bad access code");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
}
|
|
||||||
if (accessCode.isExpired()) {
|
|
||||||
logger.debug("access code expired");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
}
|
|
||||||
if (!accessCode.getToken().isActive()) {
|
|
||||||
logger.debug("access token expired");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
}
|
|
||||||
if (!accessCode.getRealm().getId().equals(realm.getId())) {
|
|
||||||
logger.debug("bad realm");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!adminConsoleUser.getLoginName().equals(accessCode.getClient().getLoginName())) {
|
|
||||||
logger.debug("bad client");
|
|
||||||
return redirectOnLoginError("invalid login data");
|
|
||||||
}
|
|
||||||
RoleModel adminConsoleAdminRole = adminConsole.getRole(Constants.ADMIN_CONSOLE_ADMIN_ROLE);
|
|
||||||
if (!realm.hasRole(accessCode.getUser(), adminConsoleAdminRole)) {
|
|
||||||
logger.debug("not allowed");
|
|
||||||
return redirectOnLoginError("No permission to access console");
|
|
||||||
}
|
|
||||||
logger.debug("loginRedirect SUCCESS");
|
logger.debug("loginRedirect SUCCESS");
|
||||||
NewCookie cookie = authManager.createSaasIdentityCookie(realm, accessCode.getUser(), uriInfo);
|
NewCookie cookie = authManager.createCookie(adminRealm, adminConsoleUser, code, AdminService.saasCookiePath(uriInfo).build());
|
||||||
|
|
||||||
URI redirectUri = contextRoot(uriInfo).path(adminPath).build();
|
URI redirectUri = contextRoot(uriInfo).path(adminPath).build();
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
|
@ -349,7 +349,7 @@ public class AdminService {
|
||||||
}
|
}
|
||||||
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
||||||
} finally {
|
} finally {
|
||||||
authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getPath());
|
expireCookie();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ public class AdminService {
|
||||||
public Response logout() {
|
public Response logout() {
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||||
authManager.expireSaasIdentityCookie(uriInfo);
|
expireCookie();
|
||||||
authManager.expireIdentityCookie(realm, uriInfo);
|
authManager.expireIdentityCookie(realm, uriInfo);
|
||||||
|
|
||||||
return Response.status(302).location(uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "loginPage").build()).build();
|
return Response.status(302).location(uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "loginPage").build()).build();
|
||||||
|
@ -370,42 +370,7 @@ public class AdminService {
|
||||||
@NoCache
|
@NoCache
|
||||||
public void logoutCookie() {
|
public void logoutCookie() {
|
||||||
logger.debug("*** logoutCookie");
|
logger.debug("*** logoutCookie");
|
||||||
authManager.expireSaasIdentityCookie(uriInfo);
|
expireCookie();
|
||||||
}
|
|
||||||
|
|
||||||
@Path("login")
|
|
||||||
@POST
|
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
|
||||||
public Response processLogin(final MultivaluedMap<String, String> formData) {
|
|
||||||
logger.debug("processLogin start");
|
|
||||||
RealmManager realmManager = new RealmManager(session);
|
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
|
||||||
if (realm == null)
|
|
||||||
throw new NotFoundException();
|
|
||||||
ApplicationModel adminConsole = realm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
|
||||||
UserModel adminConsoleUser = adminConsole.getApplicationUser();
|
|
||||||
|
|
||||||
if (!realm.isEnabled()) {
|
|
||||||
throw new NotImplementedYetException();
|
|
||||||
}
|
|
||||||
String username = formData.getFirst("username");
|
|
||||||
UserModel user = realm.getUser(username);
|
|
||||||
|
|
||||||
AuthenticationStatus status = authManager.authenticateForm(realm, user, formData);
|
|
||||||
|
|
||||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case SUCCESS:
|
|
||||||
NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
|
|
||||||
return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
|
|
||||||
case ACCOUNT_DISABLED:
|
|
||||||
return Flows.forms(realm, request, uriInfo).setError(Messages.ACCOUNT_DISABLED).setFormData(formData).createLogin();
|
|
||||||
case ACTIONS_REQUIRED:
|
|
||||||
return oauth.processAccessCode(null, "n", contextRoot(uriInfo).path(adminPath).build().toString(), adminConsoleUser, user);
|
|
||||||
default:
|
|
||||||
return Flows.forms(realm, request, uriInfo).setError(Messages.INVALID_USER).setFormData(formData).createLogin();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RealmModel getAdminstrationRealm(RealmManager realmManager) {
|
protected RealmModel getAdminstrationRealm(RealmManager realmManager) {
|
||||||
|
|
|
@ -2,10 +2,11 @@ package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
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.models.AdminRoles;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.services.managers.Auth;
|
||||||
import org.keycloak.services.managers.ModelToRepresentation;
|
import org.keycloak.services.managers.ModelToRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
import org.keycloak.services.managers.TokenManager;
|
||||||
|
@ -20,7 +21,7 @@ import javax.ws.rs.core.Context;
|
||||||
*/
|
*/
|
||||||
public class RealmAdminResource extends RoleContainerResource {
|
public class RealmAdminResource extends RoleContainerResource {
|
||||||
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
|
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
|
||||||
protected UserModel admin;
|
protected Auth auth;
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
private TokenManager tokenManager;
|
private TokenManager tokenManager;
|
||||||
|
|
||||||
|
@ -30,15 +31,17 @@ public class RealmAdminResource extends RoleContainerResource {
|
||||||
@Context
|
@Context
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
|
||||||
public RealmAdminResource(UserModel admin, RealmModel realm, TokenManager tokenManager) {
|
public RealmAdminResource(Auth auth, RealmModel realm, TokenManager tokenManager) {
|
||||||
super(realm, realm);
|
super(realm, realm);
|
||||||
this.admin = admin;
|
this.auth = auth;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.tokenManager = tokenManager;
|
this.tokenManager = tokenManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("applications")
|
@Path("applications")
|
||||||
public ApplicationsResource getApplications() {
|
public ApplicationsResource getApplications() {
|
||||||
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_APPLICATIONS);
|
||||||
|
|
||||||
ApplicationsResource applicationsResource = new ApplicationsResource(realm);
|
ApplicationsResource applicationsResource = new ApplicationsResource(realm);
|
||||||
resourceContext.initResource(applicationsResource);
|
resourceContext.initResource(applicationsResource);
|
||||||
return applicationsResource;
|
return applicationsResource;
|
||||||
|
@ -46,6 +49,8 @@ public class RealmAdminResource extends RoleContainerResource {
|
||||||
|
|
||||||
@Path("oauth-clients")
|
@Path("oauth-clients")
|
||||||
public OAuthClientsResource getOAuthClients() {
|
public OAuthClientsResource getOAuthClients() {
|
||||||
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_CLIENTS);
|
||||||
|
|
||||||
OAuthClientsResource oauth = new OAuthClientsResource(realm, session);
|
OAuthClientsResource oauth = new OAuthClientsResource(realm, session);
|
||||||
resourceContext.initResource(oauth);
|
resourceContext.initResource(oauth);
|
||||||
return oauth;
|
return oauth;
|
||||||
|
@ -55,26 +60,42 @@ public class RealmAdminResource extends RoleContainerResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces("application/json")
|
@Produces("application/json")
|
||||||
public RealmRepresentation getRealm() {
|
public RealmRepresentation getRealm() {
|
||||||
|
String realmAdminApp = AdminRoles.getAdminApp(realm);
|
||||||
|
if (auth.has(realmAdminApp, AdminRoles.MANAGE_REALM)) {
|
||||||
return ModelToRepresentation.toRepresentation(realm);
|
return ModelToRepresentation.toRepresentation(realm);
|
||||||
}
|
} else {
|
||||||
|
auth.requireOneOf(AdminRoles.getAdminApp(realm), AdminRoles.ALL_REALM_ROLES);
|
||||||
|
|
||||||
|
RealmRepresentation rep = new RealmRepresentation();
|
||||||
|
rep.setId(realm.getId());
|
||||||
|
rep.setRealm(realm.getName());
|
||||||
|
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void updateRealm(final RealmRepresentation rep) {
|
public void updateRealm(final RealmRepresentation rep) {
|
||||||
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
|
||||||
|
|
||||||
logger.debug("updating realm: " + realm.getName());
|
logger.debug("updating realm: " + realm.getName());
|
||||||
new RealmManager(session).updateRealm(rep, realm);
|
new RealmManager(session).updateRealm(rep, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
public void deleteRealms() {
|
public void deleteRealms() {
|
||||||
if (!session.removeRealm(realm.getId())) {
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
|
||||||
|
|
||||||
|
if (!new RealmManager(session).removeRealm(realm)) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("users")
|
@Path("users")
|
||||||
public UsersResource users() {
|
public UsersResource users() {
|
||||||
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_USERS);
|
||||||
|
|
||||||
UsersResource users = new UsersResource(realm, tokenManager);
|
UsersResource users = new UsersResource(realm, tokenManager);
|
||||||
resourceContext.initResource(users);
|
resourceContext.initResource(users);
|
||||||
return users;
|
return users;
|
||||||
|
@ -82,12 +103,11 @@ public class RealmAdminResource extends RoleContainerResource {
|
||||||
|
|
||||||
@Path("roles-by-id")
|
@Path("roles-by-id")
|
||||||
public RoleByIdResource rolesById() {
|
public RoleByIdResource rolesById() {
|
||||||
|
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
|
||||||
|
|
||||||
RoleByIdResource resource = new RoleByIdResource(realm);
|
RoleByIdResource resource = new RoleByIdResource(realm);
|
||||||
resourceContext.initResource(resource);
|
resourceContext.initResource(resource);
|
||||||
return resource;
|
return resource;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,13 @@ import org.jboss.resteasy.logging.Logger;
|
||||||
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
|
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
|
||||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||||
import org.jboss.resteasy.util.GenericType;
|
import org.jboss.resteasy.util.GenericType;
|
||||||
|
import org.keycloak.models.AdminRoles;
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.services.managers.Auth;
|
||||||
import org.keycloak.services.managers.ModelToRepresentation;
|
import org.keycloak.services.managers.ModelToRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
import org.keycloak.services.managers.TokenManager;
|
||||||
|
@ -35,11 +38,11 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class RealmsAdminResource {
|
public class RealmsAdminResource {
|
||||||
protected static final Logger logger = Logger.getLogger(RealmsAdminResource.class);
|
protected static final Logger logger = Logger.getLogger(RealmsAdminResource.class);
|
||||||
protected UserModel admin;
|
protected Auth auth;
|
||||||
protected TokenManager tokenManager;
|
protected TokenManager tokenManager;
|
||||||
|
|
||||||
public RealmsAdminResource(UserModel admin, TokenManager tokenManager) {
|
public RealmsAdminResource(Auth auth, TokenManager tokenManager) {
|
||||||
this.admin = admin;
|
this.auth = auth;
|
||||||
this.tokenManager = tokenManager;
|
this.tokenManager = tokenManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,11 +62,19 @@ public class RealmsAdminResource {
|
||||||
@Produces("application/json")
|
@Produces("application/json")
|
||||||
public List<RealmRepresentation> getRealms() {
|
public List<RealmRepresentation> getRealms() {
|
||||||
logger.debug(("getRealms()"));
|
logger.debug(("getRealms()"));
|
||||||
RealmManager realmManager = new RealmManager(session);
|
List<RealmModel> realms = session.getRealms();
|
||||||
List<RealmModel> realms = session.getRealms(admin);
|
|
||||||
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
||||||
for (RealmModel realm : realms) {
|
for (RealmModel realm : realms) {
|
||||||
|
String realmAdminApp = AdminRoles.getAdminApp(realm);
|
||||||
|
|
||||||
|
if (auth.has(realmAdminApp, AdminRoles.MANAGE_REALM)) {
|
||||||
reps.add(ModelToRepresentation.toRepresentation(realm));
|
reps.add(ModelToRepresentation.toRepresentation(realm));
|
||||||
|
} else if (auth.hasOneOf(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
|
||||||
|
RealmRepresentation rep = new RealmRepresentation();
|
||||||
|
rep.setId(realm.getId());
|
||||||
|
rep.setRealm(realm.getName());
|
||||||
|
reps.add(rep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return reps;
|
return reps;
|
||||||
}
|
}
|
||||||
|
@ -79,13 +90,15 @@ public class RealmsAdminResource {
|
||||||
@POST
|
@POST
|
||||||
@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) {
|
||||||
|
auth.require(AdminRoles.ADMIN);
|
||||||
|
|
||||||
logger.debug("importRealm: {0}", rep.getRealm());
|
logger.debug("importRealm: {0}", rep.getRealm());
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
if (realmManager.getRealmByName(rep.getRealm()) != null) {
|
if (realmManager.getRealmByName(rep.getRealm()) != null) {
|
||||||
return Flows.errors().exists("Realm " + rep.getRealm() + " already exists");
|
return Flows.errors().exists("Realm " + rep.getRealm() + " already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
RealmModel realm = realmManager.importRealm(rep, admin);
|
RealmModel realm = realmManager.importRealm(rep);
|
||||||
URI location = realmUrl(uriInfo).build(realm.getName());
|
URI location = realmUrl(uriInfo).build(realm.getName());
|
||||||
logger.debug("imported realm success, sending back: {0}", location.toString());
|
logger.debug("imported realm success, sending back: {0}", location.toString());
|
||||||
return Response.created(location).build();
|
return Response.created(location).build();
|
||||||
|
@ -94,6 +107,8 @@ public class RealmsAdminResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||||
public Response uploadRealm(MultipartFormDataInput input) throws IOException {
|
public Response uploadRealm(MultipartFormDataInput input) throws IOException {
|
||||||
|
auth.require(AdminRoles.ADMIN);
|
||||||
|
|
||||||
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
||||||
List<InputPart> inputParts = uploadForm.get("file");
|
List<InputPart> inputParts = uploadForm.get("file");
|
||||||
|
|
||||||
|
@ -101,7 +116,7 @@ public class RealmsAdminResource {
|
||||||
for (InputPart inputPart : inputParts) {
|
for (InputPart inputPart : inputParts) {
|
||||||
inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
|
inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
|
||||||
RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>(){});
|
RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>(){});
|
||||||
realmManager.importRealm(rep, admin);
|
realmManager.importRealm(rep);
|
||||||
}
|
}
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
}
|
}
|
||||||
|
@ -113,8 +128,11 @@ public class RealmsAdminResource {
|
||||||
RealmModel realm = realmManager.getRealmByName(name);
|
RealmModel realm = realmManager.getRealmByName(name);
|
||||||
if (realm == null) throw new NotFoundException("{realm} = " + name);
|
if (realm == null) throw new NotFoundException("{realm} = " + name);
|
||||||
|
|
||||||
RealmAdminResource adminResource = new RealmAdminResource(admin, realm, tokenManager);
|
auth.requireOneOf(AdminRoles.getAdminApp(realm), AdminRoles.ALL_REALM_ROLES);
|
||||||
|
|
||||||
|
RealmAdminResource adminResource = new RealmAdminResource(auth, realm, tokenManager);
|
||||||
resourceContext.initResource(adminResource);
|
resourceContext.initResource(adminResource);
|
||||||
return adminResource;
|
return adminResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import javax.ws.rs.BadRequestException;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.InternalServerErrorException;
|
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
|
@ -31,12 +30,10 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.ServerErrorException;
|
|
||||||
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.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -431,7 +428,7 @@ public class UsersResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
String redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
|
String redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
|
||||||
String clientId = Constants.ACCOUNT_APPLICATION;
|
String clientId = Constants.ACCOUNT_MANAGEMENT_APP;
|
||||||
String state = null;
|
String state = null;
|
||||||
String scope = null;
|
String scope = null;
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ public class KeycloakServer {
|
||||||
try {
|
try {
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
|
|
||||||
RealmModel adminRealm = manager.getRealm(Constants.ADMIN_REALM);
|
RealmModel adminRealm = manager.getKeycloakAdminstrationRealm();
|
||||||
UserModel admin = adminRealm.getUser("admin");
|
UserModel admin = adminRealm.getUser("admin");
|
||||||
admin.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
admin.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||||
|
|
||||||
|
|
|
@ -148,20 +148,6 @@ public class OAuthClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRepresentation getProfile(String token) {
|
|
||||||
HttpClient client = new DefaultHttpClient();
|
|
||||||
HttpGet get = new HttpGet(baseUrl + "/realms/" + realm + "/account");
|
|
||||||
get.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
|
|
||||||
get.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType());
|
|
||||||
|
|
||||||
try {
|
|
||||||
HttpResponse response = client.execute(get);
|
|
||||||
return JsonSerialization.readValue(response.getEntity().getContent(), UserRepresentation.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to retrieve profile", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccessToken verifyToken(String token) {
|
public AccessToken verifyToken(String token) {
|
||||||
try {
|
try {
|
||||||
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
|
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.json.JSONObject;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.models.AccountRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
@ -31,8 +32,6 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -53,7 +52,7 @@ public class ProfileTest {
|
||||||
user.setAttribute("key1", "value1");
|
user.setAttribute("key1", "value1");
|
||||||
user.setAttribute("key2", "value2");
|
user.setAttribute("key2", "value2");
|
||||||
|
|
||||||
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
|
|
||||||
UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
|
UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
|
||||||
user2.setEnabled(true);
|
user2.setEnabled(true);
|
||||||
|
@ -66,12 +65,12 @@ public class ProfileTest {
|
||||||
appRealm.updateCredential(user2, creds);
|
appRealm.updateCredential(user2, creds);
|
||||||
|
|
||||||
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
||||||
appRealm.addScopeMapping(app.getApplicationUser(), accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE));
|
appRealm.addScopeMapping(app.getApplicationUser(), accountApp.getRole(AccountRoles.VIEW_PROFILE));
|
||||||
|
|
||||||
app.getApplicationUser().addWebOrigin("http://localtest.me:8081");
|
app.getApplicationUser().addWebOrigin("http://localtest.me:8081");
|
||||||
|
|
||||||
UserModel thirdParty = appRealm.getUser("third-party");
|
UserModel thirdParty = appRealm.getUser("third-party");
|
||||||
appRealm.addScopeMapping(thirdParty, accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE));
|
appRealm.addScopeMapping(thirdParty, accountApp.getRole(AccountRoles.VIEW_PROFILE));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -175,7 +174,7 @@ public class ProfileTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProfileOAuthClient() throws Exception {
|
public void getProfileOAuthClient() throws Exception {
|
||||||
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP, AccountRoles.VIEW_PROFILE);
|
||||||
oauth.clientId("third-party");
|
oauth.clientId("third-party");
|
||||||
oauth.doLoginGrant("test-user@localhost", "password");
|
oauth.doLoginGrant("test-user@localhost", "password");
|
||||||
|
|
||||||
|
@ -192,7 +191,7 @@ public class ProfileTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProfileOAuthClientNoScope() throws Exception {
|
public void getProfileOAuthClientNoScope() throws Exception {
|
||||||
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
oauth.clientId("third-party");
|
oauth.clientId("third-party");
|
||||||
oauth.doLoginGrant("test-user@localhost", "password");
|
oauth.doLoginGrant("test-user@localhost", "password");
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class CompositeImportRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("APP_COMPOSITE_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "APP_COMPOSITE_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
|
@ -115,7 +115,7 @@ public class CompositeImportRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_APP_COMPOSITE_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_APP_COMPOSITE_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
||||||
Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
||||||
|
@ -139,7 +139,7 @@ public class CompositeImportRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_COMPOSITE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(2, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(2, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
||||||
|
@ -162,7 +162,7 @@ public class CompositeImportRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_COMPOSITE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||||
|
@ -184,7 +184,7 @@ public class CompositeImportRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_ROLE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_ROLE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||||
|
|
|
@ -168,7 +168,7 @@ public class CompositeRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("APP_COMPOSITE_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "APP_COMPOSITE_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
|
@ -193,7 +193,7 @@ public class CompositeRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_APP_COMPOSITE_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_APP_COMPOSITE_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
|
||||||
Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
||||||
|
@ -217,7 +217,7 @@ public class CompositeRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_COMPOSITE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(2, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(2, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
||||||
|
@ -240,7 +240,7 @@ public class CompositeRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_COMPOSITE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||||
|
@ -262,7 +262,7 @@ public class CompositeRoleTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
Assert.assertEquals("REALM_ROLE_1_USER", oauth.getProfile(response.getAccessToken()).getUsername());
|
Assert.assertEquals(keycloakRule.getUser("Test", "REALM_ROLE_1_USER").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.forms;
|
package org.keycloak.testsuite.forms;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.keycloak.models.*;
|
import org.keycloak.models.*;
|
||||||
import org.keycloak.models.utils.TimeBasedOTP;
|
import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
|
@ -35,10 +34,6 @@ import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
|
||||||
import org.openqa.selenium.support.FindBy;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@ -53,7 +48,7 @@ public class AccountTest {
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
UserModel user = appRealm.getUser("test-user@localhost");
|
UserModel user = appRealm.getUser("test-user@localhost");
|
||||||
|
|
||||||
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP);
|
||||||
|
|
||||||
UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
|
UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
|
||||||
user2.setEnabled(true);
|
user2.setEnabled(true);
|
||||||
|
|
|
@ -25,8 +25,10 @@ import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
@ -70,11 +72,8 @@ public class AccessTokenTest {
|
||||||
|
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
UserRepresentation user = oauth.getProfile(response.getAccessToken());
|
Assert.assertEquals(keycloakRule.getUser("test", "test-user@localhost").getId(), token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals(user.getId(), token.getSubject());
|
|
||||||
Assert.assertNotEquals("test-user@localhost", token.getSubject());
|
Assert.assertNotEquals("test-user@localhost", token.getSubject());
|
||||||
Assert.assertEquals("test-user@localhost", user.getUsername());
|
|
||||||
|
|
||||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
|
Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
|
||||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.services.managers.ModelToRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.testutils.KeycloakServer;
|
import org.keycloak.testutils.KeycloakServer;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
@ -31,6 +33,24 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||||
setupKeycloak();
|
setupKeycloak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserRepresentation getUser(String realm, String name) {
|
||||||
|
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||||
|
try {
|
||||||
|
return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUser(name));
|
||||||
|
} finally {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRepresentation getUserById(String realm, String id) {
|
||||||
|
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||||
|
try {
|
||||||
|
return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUserById(id));
|
||||||
|
} finally {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void setupKeycloak() {
|
protected void setupKeycloak() {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
|
@ -26,6 +26,9 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.models.AccountRoles;
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
@ -107,7 +110,7 @@ public class SocialLoginTest {
|
||||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
Assert.assertEquals(36, token.getSubject().length());
|
Assert.assertEquals(36, token.getSubject().length());
|
||||||
|
|
||||||
UserRepresentation profile = oauth.getProfile(response.getAccessToken());
|
UserRepresentation profile = keycloakRule.getUserById("test", token.getSubject());
|
||||||
Assert.assertEquals(36, profile.getUsername().length());
|
Assert.assertEquals(36, profile.getUsername().length());
|
||||||
|
|
||||||
Assert.assertEquals("Bob", profile.getFirstName());
|
Assert.assertEquals("Bob", profile.getFirstName());
|
||||||
|
@ -146,7 +149,9 @@ public class SocialLoginTest {
|
||||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
|
||||||
AccessTokenResponse response = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
|
AccessTokenResponse response = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
|
||||||
UserRepresentation profile = oauth.getProfile(response.getAccessToken());
|
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||||
|
|
||||||
|
UserRepresentation profile = keycloakRule.getUserById("test", token.getSubject());
|
||||||
|
|
||||||
Assert.assertEquals("Dummy", profile.getFirstName());
|
Assert.assertEquals("Dummy", profile.getFirstName());
|
||||||
Assert.assertEquals("User", profile.getLastName());
|
Assert.assertEquals("User", profile.getLastName());
|
||||||
|
|
Loading…
Reference in a new issue