Merge pull request #240 from stianst/admin-access
KEYCLOAK-292 Fine-grained admin control
This commit is contained in:
commit
fa39ec1c98
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) {
|
||||
Auth.user = data;
|
||||
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) {
|
||||
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');
|
||||
|
||||
Current.realm = null;
|
||||
|
@ -131,8 +142,14 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
|||
Current.realm = Current.realms[i];
|
||||
}
|
||||
}
|
||||
$location.url("/realms/" + realmCopy.realm);
|
||||
Notifications.success("The realm has been created.");
|
||||
|
||||
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
|
||||
Auth.user = data;
|
||||
console.log("reloaded auth");
|
||||
|
||||
$location.url("/realms/" + realmCopy.realm);
|
||||
Notifications.success("The realm has been created.");
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</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'"
|
||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||
</li>
|
||||
|
|
|
@ -7,98 +7,104 @@
|
|||
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
||||
<li class="active">General</li>
|
||||
</ol>
|
||||
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</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>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset>
|
||||
<legend class="aj-collapse open"><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="createRealm">*</span></label>
|
||||
<div data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')">
|
||||
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</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>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset>
|
||||
<legend class="aj-collapse open"><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="createRealm">*</span></label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="name" name="name" data-ng-model="realm.realm" autofocus required>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="name" name="name" data-ng-model="realm.realm" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="enabled">Enabled</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="enabled">Enabled</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Login Options</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="social">Social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.social" name="social" id="social" onoffswitch />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Login Options</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="social">Social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.social" name="social" id="social" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.social">
|
||||
<label class="col-sm-2 control-label" for="updateProfileOnInitialSocialLogin">Update profile on first social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.updateProfileOnInitialSocialLogin" name="updateProfileOnInitialSocialLogin" id="updateProfileOnInitialSocialLogin" onoffswitch />
|
||||
<div class="form-group" data-ng-show="realm.social">
|
||||
<label class="col-sm-2 control-label" for="updateProfileOnInitialSocialLogin">Update profile on first social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.updateProfileOnInitialSocialLogin" name="updateProfileOnInitialSocialLogin" id="updateProfileOnInitialSocialLogin" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="registrationAllowed" class="col-sm-2 control-label">User registration</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="registrationAllowed" class="col-sm-2 control-label">User registration</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="resetPasswordAllowed" class="col-sm-2 control-label">Reset password</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="resetPasswordAllowed" class="col-sm-2 control-label">Reset password</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="verifyEmail" class="col-sm-2 control-label">Verify email</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="verifyEmail" class="col-sm-2 control-label">Verify email</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="requireSsl" class="col-sm-2 control-label">Require SSL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="requireSsl" class="col-sm-2 control-label">Require SSL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Optional Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="loginTheme">Login Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="loginTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.loginTheme"
|
||||
data-kc-options="serverInfo.themes.login">
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Optional Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="loginTheme">Login Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="loginTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.loginTheme"
|
||||
data-kc-options="serverInfo.themes.login">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accountTheme">Account Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="accountTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.accountTheme"
|
||||
data-kc-options="serverInfo.themes.account">
|
||||
</select>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accountTheme">Account Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="accountTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.accountTheme"
|
||||
data-kc-options="serverInfo.themes.account">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="createRealm">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!createRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div data-ng-hide="auth.hasAccess(realm.realm, 'manage-realm')">
|
||||
<h2 ><span>{{realm.realm}}</span></h2>
|
||||
</div>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="createRealm">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!createRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,10 +1,9 @@
|
|||
<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] == '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 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>
|
||||
</ul>
|
||||
|
||||
<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-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>
|
|
@ -1,10 +1,10 @@
|
|||
<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 == 'social'}" data-ng-show="kcSocial"><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 == 'defRoles'}"><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 == 'token'}"><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 == 'email'}"><a href="#/realms/{{kcRealm}}/smtp-settings">Email</a></li>
|
||||
</ul>
|
||||
<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'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/roles">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'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/required-credentials">Credentials</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'}" data-ng-show="auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{kcRealm}}/keys-settings">Keys</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>
|
|
@ -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 $
|
||||
*/
|
||||
public interface Constants {
|
||||
String INTERNAL_ROLE = "KEYCLOAK_";
|
||||
String ADMIN_REALM = "keycloak-admin";
|
||||
String ADMIN_CONSOLE_APPLICATION = "admin-console";
|
||||
String ADMIN_CONSOLE_ADMIN_ROLE = "admin";
|
||||
|
||||
String INTERNAL_ROLE = "KEYCLOAK_";
|
||||
String APPLICATION_ROLE = INTERNAL_ROLE + "_APPLICATION";
|
||||
String IDENTITY_REQUESTER_ROLE = INTERNAL_ROLE + "_IDENTITY_REQUESTER";
|
||||
|
||||
String ACCOUNT_APPLICATION = "account";
|
||||
String ACCOUNT_PROFILE_ROLE = "view-profile";
|
||||
String ACCOUNT_MANAGE_ROLE = "manage-account";
|
||||
String ACCOUNT_MANAGEMENT_APP = "account";
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public interface KeycloakSession {
|
|||
RealmModel createRealm(String id, String name);
|
||||
RealmModel getRealm(String id);
|
||||
RealmModel getRealmByName(String name);
|
||||
List<RealmModel> getRealms(UserModel admin);
|
||||
List<RealmModel> getRealms();
|
||||
boolean removeRealm(String id);
|
||||
|
||||
void close();
|
||||
|
|
|
@ -49,7 +49,7 @@ public class JpaKeycloakSession implements KeycloakSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<RealmModel> getRealms(UserModel admin) {
|
||||
public List<RealmModel> getRealms() {
|
||||
TypedQuery<RealmEntity> query = em.createNamedQuery("getAllRealms", RealmEntity.class);
|
||||
List<RealmEntity> entities = query.getResultList();
|
||||
List<RealmModel> realms = new ArrayList<RealmModel>();
|
||||
|
|
|
@ -67,7 +67,7 @@ public class MongoKeycloakSession implements KeycloakSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<RealmModel> getRealms(UserModel admin) {
|
||||
public List<RealmModel> getRealms() {
|
||||
DBObject query = new BasicDBObject();
|
||||
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.RoleModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
@ -34,6 +35,8 @@ public class AbstractModelTest {
|
|||
identitySession = factory.createSession();
|
||||
identitySession.getTransaction().begin();
|
||||
realmManager = new RealmManager(identitySession);
|
||||
|
||||
new ApplianceBootstrap().bootstrap(identitySession);
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.model.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
@ -32,12 +33,6 @@ import java.util.Set;
|
|||
public class AdapterTest extends AbstractModelTest {
|
||||
private RealmModel realmModel;
|
||||
|
||||
@Test
|
||||
public void installTest() throws Exception {
|
||||
new ApplianceBootstrap().bootstrap(identitySession);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1CreateRealm() throws Exception {
|
||||
realmModel = realmManager.createRealm("JUGGLER");
|
||||
|
@ -79,7 +74,6 @@ public class AdapterTest extends AbstractModelTest {
|
|||
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
||||
realmModel.addDefaultRole("foo");
|
||||
|
||||
System.out.println(realmModel.getId());
|
||||
realmModel = realmManager.getRealm(realmModel.getId());
|
||||
Assert.assertNotNull(realmModel);
|
||||
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
||||
|
@ -93,13 +87,11 @@ public class AdapterTest extends AbstractModelTest {
|
|||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
||||
|
||||
String id = realmModel.getId();
|
||||
System.out.println("id: " + id);
|
||||
realmModel.getId();
|
||||
|
||||
commit();
|
||||
List<RealmModel> realms = identitySession.getRealms(null);
|
||||
System.out.println("num realms: " + realms.size());
|
||||
Assert.assertEquals(realms.size(), 1);
|
||||
List<RealmModel> realms = identitySession.getRealms();
|
||||
Assert.assertEquals(realms.size(), 2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.junit.Assert;
|
|||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -56,7 +57,7 @@ public class ImportTest extends AbstractModelTest {
|
|||
// Test applications imported
|
||||
ApplicationModel application = realm.getApplicationByName("Application");
|
||||
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");
|
||||
Assert.assertNotNull(application);
|
||||
Assert.assertNotNull(otherApp);
|
||||
|
@ -80,8 +81,8 @@ public class ImportTest extends AbstractModelTest {
|
|||
Assert.assertTrue(allRoles.contains(realm.getRole("admin")));
|
||||
Assert.assertTrue(allRoles.contains(application.getRole("app-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(Constants.ACCOUNT_MANAGE_ROLE)));
|
||||
Assert.assertTrue(allRoles.contains(accountApp.getRole(AccountRoles.VIEW_PROFILE)));
|
||||
Assert.assertTrue(allRoles.contains(accountApp.getRole(AccountRoles.MANAGE_ACCOUNT)));
|
||||
|
||||
UserModel wburke = realm.getUser("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;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -62,7 +63,9 @@ public class ApplianceBootstrap {
|
|||
adminConsole.setBaseUrl("/auth/admin/index.html");
|
||||
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");
|
||||
adminUser.setEnabled(true);
|
||||
|
@ -74,7 +77,7 @@ public class ApplianceBootstrap {
|
|||
|
||||
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()) {
|
||||
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.representations.AccessToken;
|
||||
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 javax.ws.rs.NotAuthorizedException;
|
||||
import javax.ws.rs.core.Cookie;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
@ -59,19 +56,6 @@ public class AuthenticationManager {
|
|||
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) {
|
||||
AccessToken identityToken = createIdentityToken(realm, user);
|
||||
if (client != null) {
|
||||
|
@ -104,7 +88,6 @@ public class AuthenticationManager {
|
|||
return encodedToken;
|
||||
}
|
||||
|
||||
|
||||
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
|
||||
logger.debug("Expiring identity cookie");
|
||||
String path = getIdentityCookiePath(realm, uriInfo);
|
||||
|
@ -123,17 +106,6 @@ public class AuthenticationManager {
|
|||
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) {
|
||||
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
|
||||
if (response == null) {
|
||||
|
@ -149,42 +121,13 @@ public class AuthenticationManager {
|
|||
return authenticateIdentityCookie(realm, uriInfo, headers, true);
|
||||
}
|
||||
|
||||
|
||||
public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, boolean checkActive) {
|
||||
logger.info("authenticateIdentityCookie");
|
||||
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
||||
Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName, checkActive);
|
||||
return auth != null ? auth.getUser() : null;
|
||||
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName, checkActive);
|
||||
}
|
||||
|
||||
public UserModel authenticateSaasIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
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) {
|
||||
protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName, boolean checkActive) {
|
||||
logger.info("authenticateIdentityCookie");
|
||||
Cookie cookie = headers.getCookies().get(cookieName);
|
||||
if (cookie == null) {
|
||||
|
@ -202,27 +145,14 @@ public class AuthenticationManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
Auth auth = new Auth(token);
|
||||
|
||||
UserModel user = realm.getUserById(token.getSubject());
|
||||
if (user == null || !user.isEnabled()) {
|
||||
logger.info("Unknown user in identity cookie");
|
||||
expireIdentityCookie(realm, uriInfo);
|
||||
return null;
|
||||
}
|
||||
auth.setUser(user);
|
||||
|
||||
if (token.getIssuedFor() != null) {
|
||||
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;
|
||||
return user;
|
||||
} catch (VerificationException e) {
|
||||
logger.info("Failed to verify identity cookie", e);
|
||||
expireCookie(cookie.getName(), cookie.getPath());
|
||||
|
@ -230,49 +160,6 @@ public class AuthenticationManager {
|
|||
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) {
|
||||
if (user == null) {
|
||||
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
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||
|
||||
List<String> defaultRoles = realm.getDefaultRoles();
|
||||
if (!defaultRoles.isEmpty()) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.keycloak.services.managers;
|
||||
|
||||
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.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -59,7 +61,6 @@ public class RealmManager {
|
|||
return identitySession.getRealmByName(name);
|
||||
}
|
||||
|
||||
|
||||
public RealmModel createRealm(String name) {
|
||||
return createRealm(name, name);
|
||||
}
|
||||
|
@ -71,13 +72,31 @@ public class RealmManager {
|
|||
realm.addRole(Constants.APPLICATION_ROLE);
|
||||
realm.addRole(Constants.IDENTITY_REQUESTER_ROLE);
|
||||
|
||||
setupAdminManagement(realm);
|
||||
setupAccountManagement(realm);
|
||||
|
||||
realm.addRequiredOAuthClientCredential(UserCredentialModel.SECRET);
|
||||
realm.addRequiredResourceCredential(UserCredentialModel.SECRET);
|
||||
|
||||
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) {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
|
@ -134,19 +153,41 @@ public class RealmManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void setupAccountManagement(RealmModel realm) {
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
if (application == null) {
|
||||
application = new ApplicationManager(this).createApplication(realm, Constants.ACCOUNT_APPLICATION);
|
||||
application.setEnabled(true);
|
||||
private void setupAdminManagement(RealmModel realm) {
|
||||
RealmModel adminRealm;
|
||||
RoleModel adminRole;
|
||||
|
||||
application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE);
|
||||
application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public RealmModel importRealm(RealmRepresentation rep, UserModel realmCreator) {
|
||||
private void setupAccountManagement(RealmModel realm) {
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||
if (application == null) {
|
||||
application = new ApplicationManager(this).createApplication(realm, Constants.ACCOUNT_MANAGEMENT_APP);
|
||||
application.setEnabled(true);
|
||||
|
||||
for (String role : AccountRoles.ALL) {
|
||||
application.addDefaultRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RealmModel importRealm(RealmRepresentation rep) {
|
||||
String id = rep.getId();
|
||||
if (id == null) {
|
||||
id = KeycloakModelUtils.generateId();
|
||||
|
@ -299,7 +340,6 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
|
||||
|
||||
if (rep.getRoleMappings() != null) {
|
||||
for (UserRoleMappingRepresentation mapping : rep.getRoleMappings()) {
|
||||
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.spi.HttpRequest;
|
||||
import org.keycloak.AbstractOAuthClient;
|
||||
import org.keycloak.account.Account;
|
||||
import org.keycloak.account.AccountLoader;
|
||||
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.models.*;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
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.TokenManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
|
@ -68,23 +67,23 @@ public class AccountService {
|
|||
@Context
|
||||
private UriInfo uriInfo;
|
||||
|
||||
private AuthenticationManager authManager = new AuthenticationManager();
|
||||
private AppAuthManager authManager;
|
||||
|
||||
private ApplicationModel application;
|
||||
|
||||
private TokenManager tokenManager;
|
||||
|
||||
public AccountService(RealmModel realm, ApplicationModel application, TokenManager tokenManager) {
|
||||
this.realm = realm;
|
||||
this.application = application;
|
||||
this.tokenManager = tokenManager;
|
||||
this.authManager = new AppAuthManager("KEYCLOAK_ACCOUNT_IDENTITY", tokenManager);
|
||||
}
|
||||
|
||||
private Response forwardToPage(String path, AccountPages page) {
|
||||
AuthenticationManager.Auth auth = getAuth(false);
|
||||
Auth auth = getAuth(false);
|
||||
if (auth != null) {
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
try {
|
||||
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());
|
||||
|
@ -100,10 +99,6 @@ public class AccountService {
|
|||
}
|
||||
}
|
||||
|
||||
private Response noAccess() {
|
||||
return Flows.forms(realm, request, uriInfo).setError("No access").createErrorPage();
|
||||
}
|
||||
|
||||
@Path("/")
|
||||
@OPTIONS
|
||||
public Response accountPreflight() {
|
||||
|
@ -117,10 +112,9 @@ public class AccountService {
|
|||
if (types.contains(MediaType.WILDCARD_TYPE) || (types.contains(MediaType.TEXT_HTML_TYPE))) {
|
||||
return forwardToPage(null, AccountPages.ACCOUNT);
|
||||
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) {
|
||||
return Response.status(Response.Status.FORBIDDEN).build();
|
||||
}
|
||||
Auth auth = getAuth(true);
|
||||
auth.requireOneOf(application, AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
|
||||
|
||||
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
|
||||
} else {
|
||||
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
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
Auth auth = getAuth(true);
|
||||
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
|
@ -167,10 +159,8 @@ public class AccountService {
|
|||
@Path("totp-remove")
|
||||
@GET
|
||||
public Response processTotpRemove() {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
Auth auth = getAuth(true);
|
||||
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
user.setTotp(false);
|
||||
|
@ -183,10 +173,8 @@ public class AccountService {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
Auth auth = getAuth(true);
|
||||
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
|
@ -215,10 +203,8 @@ public class AccountService {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
Auth auth = getAuth(true);
|
||||
auth.require(application, AccountRoles.MANAGE_ACCOUNT);
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
|
@ -285,61 +271,25 @@ public class AccountService {
|
|||
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 redirectUri = path != null ? accountUri.resolve(path) : accountUri;
|
||||
if (referrer != null) {
|
||||
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();
|
||||
} finally {
|
||||
authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getRawPath());
|
||||
authManager.expireCookie(Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Path("logout")
|
||||
@GET
|
||||
public Response logout() {
|
||||
// TODO Should use single-sign out via TokenService
|
||||
URI baseUri = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
|
||||
authManager.expireIdentityCookie(realm, uriInfo);
|
||||
authManager.expireAccountIdentityCookie(baseUri);
|
||||
authManager.expireCookie(baseUri);
|
||||
return Response.status(302).location(baseUri).build();
|
||||
}
|
||||
|
||||
|
@ -348,7 +298,7 @@ public class AccountService {
|
|||
String authUrl = Urls.realmLoginPage(uriInfo.getBaseUri(), realm.getName()).toString();
|
||||
oauth.setAuthUrl(authUrl);
|
||||
|
||||
oauth.setClientId(Constants.ACCOUNT_APPLICATION);
|
||||
oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_APP);
|
||||
|
||||
UriBuilder uriBuilder = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect");
|
||||
|
||||
|
@ -368,42 +318,14 @@ public class AccountService {
|
|||
return oauth.redirect(uriInfo, accountUri.toString());
|
||||
}
|
||||
|
||||
private AuthenticationManager.Auth getAuth(boolean error) {
|
||||
AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers);
|
||||
private Auth getAuth(boolean error) {
|
||||
Auth auth = authManager.authenticate(realm, headers);
|
||||
if (auth == null && error) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
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() {
|
||||
String referrer = uriInfo.getQueryParameters().getFirst("referrer");
|
||||
if (referrer != null) {
|
||||
|
|
|
@ -69,7 +69,7 @@ public class RealmsResource {
|
|||
RealmManager realmManager = new RealmManager(session);
|
||||
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()) {
|
||||
logger.debug("account management not enabled");
|
||||
throw new NotFoundException();
|
||||
|
|
|
@ -1,49 +1,44 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.jboss.resteasy.spi.NotImplementedYetException;
|
||||
import org.keycloak.AbstractOAuthClient;
|
||||
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
|
||||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
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.NotAuthorizedException;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.container.ResourceContext;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.ext.Providers;
|
||||
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>
|
||||
|
@ -52,8 +47,6 @@ import java.net.URI;
|
|||
@Path("/admin")
|
||||
public class AdminService {
|
||||
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
|
||||
protected UriInfo uriInfo;
|
||||
|
@ -73,25 +66,32 @@ public class AdminService {
|
|||
@Context
|
||||
protected Providers providers;
|
||||
|
||||
|
||||
protected String adminPath = "/admin/index.html";
|
||||
protected AuthenticationManager authManager = new AuthenticationManager();
|
||||
protected AppAuthManager authManager;
|
||||
protected TokenManager tokenManager;
|
||||
|
||||
public AdminService(TokenManager tokenManager) {
|
||||
this.tokenManager = tokenManager;
|
||||
this.authManager = new AppAuthManager("KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager);
|
||||
}
|
||||
|
||||
public static class WhoAmI {
|
||||
protected String userId;
|
||||
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(String userId, String displayName) {
|
||||
public WhoAmI(String userId, String displayName, boolean admin, Map<String, Set<String>> realmAccess) {
|
||||
this.userId = userId;
|
||||
this.displayName = displayName;
|
||||
this.admin = admin;
|
||||
this.realmAccess = realmAccess;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
|
@ -109,6 +109,22 @@ public class AdminService {
|
|||
public void setDisplayName(String 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")
|
||||
|
@ -120,11 +136,11 @@ public class AdminService {
|
|||
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||
if (realm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
if (user == null) {
|
||||
Auth auth = authManager.authenticateCookie(realm, headers);
|
||||
if (auth == null) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -137,15 +153,50 @@ public class AdminService {
|
|||
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||
if (realm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
Auth auth = authManager.authenticateCookie(realm, headers);
|
||||
UserModel user = auth.getUser();
|
||||
if (user == null) {
|
||||
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();
|
||||
}
|
||||
|
||||
@Path("isLoggedIn.js")
|
||||
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")
|
||||
@GET
|
||||
@Produces("application/javascript")
|
||||
@NoCache
|
||||
|
@ -157,7 +208,7 @@ public class AdminService {
|
|||
return "var keycloakCookieLoggedIn = false;";
|
||||
|
||||
}
|
||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
UserModel user = authManager.authenticateCookie(realm, headers).getUser();
|
||||
if (user == null) {
|
||||
return "var keycloakCookieLoggedIn = false;";
|
||||
}
|
||||
|
@ -176,23 +227,14 @@ public class AdminService {
|
|||
@Path("realms")
|
||||
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel saasRealm = getAdminstrationRealm(realmManager);
|
||||
if (saasRealm == null)
|
||||
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||
if (adminRealm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
|
||||
if (admin == null) {
|
||||
Auth auth = authManager.authenticate(adminRealm, headers);
|
||||
if (auth == null) {
|
||||
throw new NotAuthorizedException("Bearer");
|
||||
}
|
||||
ApplicationModel adminConsole = saasRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||
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);
|
||||
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
|
||||
resourceContext.initResource(adminResource);
|
||||
return adminResource;
|
||||
}
|
||||
|
@ -200,35 +242,33 @@ public class AdminService {
|
|||
@Path("serverinfo")
|
||||
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel saasRealm = getAdminstrationRealm(realmManager);
|
||||
if (saasRealm == null)
|
||||
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||
if (adminRealm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
|
||||
Auth auth = authManager.authenticate(adminRealm, headers);
|
||||
UserModel admin = auth.getUser();
|
||||
if (admin == null) {
|
||||
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) {
|
||||
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();
|
||||
resourceContext.initResource(adminResource);
|
||||
return adminResource;
|
||||
}
|
||||
|
||||
private void expireCookie() {
|
||||
authManager.expireCookie(AdminService.saasCookiePath(uriInfo).build());
|
||||
}
|
||||
|
||||
@Path("login")
|
||||
@GET
|
||||
@NoCache
|
||||
public Response loginPage(@QueryParam("path") String path) {
|
||||
logger.debug("loginPage ********************** <---");
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
expireCookie();
|
||||
|
||||
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
||||
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 logout = TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", uri.toString()).build(Constants.ADMIN_REALM);
|
||||
return Response.status(302).location(logout).build();
|
||||
|
||||
}
|
||||
|
||||
@Path("login-redirect")
|
||||
|
@ -279,12 +318,12 @@ public class AdminService {
|
|||
return redirectOnLoginError(error);
|
||||
}
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||
if (!realm.isEnabled()) {
|
||||
RealmModel adminRealm = getAdminstrationRealm(realmManager);
|
||||
if (!adminRealm.isEnabled()) {
|
||||
logger.debug("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();
|
||||
if (!adminConsole.isEnabled() || !adminConsoleUser.isEnabled()) {
|
||||
logger.debug("admin app not enabled");
|
||||
|
@ -301,47 +340,8 @@ public class AdminService {
|
|||
}
|
||||
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");
|
||||
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();
|
||||
if (path != null) {
|
||||
|
@ -349,7 +349,7 @@ public class AdminService {
|
|||
}
|
||||
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
||||
} finally {
|
||||
authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getPath());
|
||||
expireCookie();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ public class AdminService {
|
|||
public Response logout() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
expireCookie();
|
||||
authManager.expireIdentityCookie(realm, uriInfo);
|
||||
|
||||
return Response.status(302).location(uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "loginPage").build()).build();
|
||||
|
@ -370,42 +370,7 @@ public class AdminService {
|
|||
@NoCache
|
||||
public void logoutCookie() {
|
||||
logger.debug("*** logoutCookie");
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
expireCookie();
|
||||
}
|
||||
|
||||
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.logging.Logger;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
|
@ -20,7 +21,7 @@ import javax.ws.rs.core.Context;
|
|||
*/
|
||||
public class RealmAdminResource extends RoleContainerResource {
|
||||
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
|
||||
protected UserModel admin;
|
||||
protected Auth auth;
|
||||
protected RealmModel realm;
|
||||
private TokenManager tokenManager;
|
||||
|
||||
|
@ -30,15 +31,17 @@ public class RealmAdminResource extends RoleContainerResource {
|
|||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
public RealmAdminResource(UserModel admin, RealmModel realm, TokenManager tokenManager) {
|
||||
public RealmAdminResource(Auth auth, RealmModel realm, TokenManager tokenManager) {
|
||||
super(realm, realm);
|
||||
this.admin = admin;
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
@Path("applications")
|
||||
public ApplicationsResource getApplications() {
|
||||
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_APPLICATIONS);
|
||||
|
||||
ApplicationsResource applicationsResource = new ApplicationsResource(realm);
|
||||
resourceContext.initResource(applicationsResource);
|
||||
return applicationsResource;
|
||||
|
@ -46,6 +49,8 @@ public class RealmAdminResource extends RoleContainerResource {
|
|||
|
||||
@Path("oauth-clients")
|
||||
public OAuthClientsResource getOAuthClients() {
|
||||
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_CLIENTS);
|
||||
|
||||
OAuthClientsResource oauth = new OAuthClientsResource(realm, session);
|
||||
resourceContext.initResource(oauth);
|
||||
return oauth;
|
||||
|
@ -55,26 +60,42 @@ public class RealmAdminResource extends RoleContainerResource {
|
|||
@NoCache
|
||||
@Produces("application/json")
|
||||
public RealmRepresentation getRealm() {
|
||||
return ModelToRepresentation.toRepresentation(realm);
|
||||
}
|
||||
String realmAdminApp = AdminRoles.getAdminApp(realm);
|
||||
if (auth.has(realmAdminApp, AdminRoles.MANAGE_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
|
||||
@Consumes("application/json")
|
||||
public void updateRealm(final RealmRepresentation rep) {
|
||||
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
|
||||
|
||||
logger.debug("updating realm: " + realm.getName());
|
||||
new RealmManager(session).updateRealm(rep, realm);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Path("users")
|
||||
public UsersResource users() {
|
||||
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_USERS);
|
||||
|
||||
UsersResource users = new UsersResource(realm, tokenManager);
|
||||
resourceContext.initResource(users);
|
||||
return users;
|
||||
|
@ -82,12 +103,11 @@ public class RealmAdminResource extends RoleContainerResource {
|
|||
|
||||
@Path("roles-by-id")
|
||||
public RoleByIdResource rolesById() {
|
||||
auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
|
||||
|
||||
RoleByIdResource resource = new RoleByIdResource(realm);
|
||||
resourceContext.initResource(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.MultipartFormDataInput;
|
||||
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.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
|
@ -35,11 +38,11 @@ import java.util.Map;
|
|||
*/
|
||||
public class RealmsAdminResource {
|
||||
protected static final Logger logger = Logger.getLogger(RealmsAdminResource.class);
|
||||
protected UserModel admin;
|
||||
protected Auth auth;
|
||||
protected TokenManager tokenManager;
|
||||
|
||||
public RealmsAdminResource(UserModel admin, TokenManager tokenManager) {
|
||||
this.admin = admin;
|
||||
public RealmsAdminResource(Auth auth, TokenManager tokenManager) {
|
||||
this.auth = auth;
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
|
@ -59,11 +62,19 @@ public class RealmsAdminResource {
|
|||
@Produces("application/json")
|
||||
public List<RealmRepresentation> getRealms() {
|
||||
logger.debug(("getRealms()"));
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
List<RealmModel> realms = session.getRealms(admin);
|
||||
List<RealmModel> realms = session.getRealms();
|
||||
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
||||
for (RealmModel realm : realms) {
|
||||
reps.add(ModelToRepresentation.toRepresentation(realm));
|
||||
String realmAdminApp = AdminRoles.getAdminApp(realm);
|
||||
|
||||
if (auth.has(realmAdminApp, AdminRoles.MANAGE_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;
|
||||
}
|
||||
|
@ -79,13 +90,15 @@ public class RealmsAdminResource {
|
|||
@POST
|
||||
@Consumes("application/json")
|
||||
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
|
||||
auth.require(AdminRoles.ADMIN);
|
||||
|
||||
logger.debug("importRealm: {0}", rep.getRealm());
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
if (realmManager.getRealmByName(rep.getRealm()) != null) {
|
||||
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());
|
||||
logger.debug("imported realm success, sending back: {0}", location.toString());
|
||||
return Response.created(location).build();
|
||||
|
@ -94,6 +107,8 @@ public class RealmsAdminResource {
|
|||
@POST
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
public Response uploadRealm(MultipartFormDataInput input) throws IOException {
|
||||
auth.require(AdminRoles.ADMIN);
|
||||
|
||||
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
||||
List<InputPart> inputParts = uploadForm.get("file");
|
||||
|
||||
|
@ -101,7 +116,7 @@ public class RealmsAdminResource {
|
|||
for (InputPart inputPart : inputParts) {
|
||||
inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
|
||||
RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>(){});
|
||||
realmManager.importRealm(rep, admin);
|
||||
realmManager.importRealm(rep);
|
||||
}
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
@ -113,8 +128,11 @@ public class RealmsAdminResource {
|
|||
RealmModel realm = realmManager.getRealmByName(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);
|
||||
return adminResource;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import javax.ws.rs.BadRequestException;
|
|||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.InternalServerErrorException;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
|
@ -31,12 +30,10 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.ServerErrorException;
|
||||
import javax.ws.rs.container.ResourceContext;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -431,7 +428,7 @@ public class UsersResource {
|
|||
}
|
||||
|
||||
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 scope = null;
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ public class KeycloakServer {
|
|||
try {
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
||||
RealmModel adminRealm = manager.getRealm(Constants.ADMIN_REALM);
|
||||
RealmModel adminRealm = manager.getKeycloakAdminstrationRealm();
|
||||
UserModel admin = adminRealm.getUser("admin");
|
||||
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) {
|
||||
try {
|
||||
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.json.JSONObject;
|
|||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
|
@ -31,8 +32,6 @@ import javax.ws.rs.core.MediaType;
|
|||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -53,7 +52,7 @@ public class ProfileTest {
|
|||
user.setAttribute("key1", "value1");
|
||||
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");
|
||||
user2.setEnabled(true);
|
||||
|
@ -66,12 +65,12 @@ public class ProfileTest {
|
|||
appRealm.updateCredential(user2, creds);
|
||||
|
||||
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");
|
||||
|
||||
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
|
||||
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.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
|
@ -192,7 +191,7 @@ public class ProfileTest {
|
|||
|
||||
@Test
|
||||
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.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ public class CompositeImportRoleTest {
|
|||
|
||||
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.getRealmAccess().getRoles().size());
|
||||
|
@ -115,7 +115,7 @@ public class CompositeImportRoleTest {
|
|||
|
||||
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.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
||||
|
@ -139,7 +139,7 @@ public class CompositeImportRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
||||
|
@ -162,7 +162,7 @@ public class CompositeImportRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||
|
@ -184,7 +184,7 @@ public class CompositeImportRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||
|
|
|
@ -168,7 +168,7 @@ public class CompositeRoleTest {
|
|||
|
||||
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.getRealmAccess().getRoles().size());
|
||||
|
@ -193,7 +193,7 @@ public class CompositeRoleTest {
|
|||
|
||||
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.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
|
||||
|
@ -217,7 +217,7 @@ public class CompositeRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1"));
|
||||
|
@ -240,7 +240,7 @@ public class CompositeRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||
|
@ -262,7 +262,7 @@ public class CompositeRoleTest {
|
|||
|
||||
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.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.forms;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.junit.*;
|
||||
import org.keycloak.models.*;
|
||||
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.WebRule;
|
||||
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;
|
||||
|
||||
|
@ -53,7 +48,7 @@ public class AccountTest {
|
|||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
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");
|
||||
user2.setEnabled(true);
|
||||
|
|
|
@ -25,8 +25,10 @@ import org.junit.Assert;
|
|||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
|
@ -70,11 +72,8 @@ public class AccessTokenTest {
|
|||
|
||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||
|
||||
UserRepresentation user = oauth.getProfile(response.getAccessToken());
|
||||
|
||||
Assert.assertEquals(user.getId(), token.getSubject());
|
||||
Assert.assertEquals(keycloakRule.getUser("test", "test-user@localhost").getId(), token.getSubject());
|
||||
Assert.assertNotEquals("test-user@localhost", token.getSubject());
|
||||
Assert.assertEquals("test-user@localhost", user.getUsername());
|
||||
|
||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.models.Constants;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
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.testutils.KeycloakServer;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
@ -31,6 +33,24 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
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() {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
session.getTransaction().begin();
|
||||
|
|
|
@ -26,6 +26,9 @@ import org.junit.BeforeClass;
|
|||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
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.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
@ -107,7 +110,7 @@ public class SocialLoginTest {
|
|||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||
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("Bob", profile.getFirstName());
|
||||
|
@ -146,7 +149,9 @@ public class SocialLoginTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
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("User", profile.getLastName());
|
||||
|
|
Loading…
Reference in a new issue