app password

This commit is contained in:
Bill Burke 2013-10-06 18:41:35 -04:00
parent 3a8c1e54d5
commit 7613df71c2
28 changed files with 572 additions and 125 deletions

View file

@ -12,6 +12,7 @@ public class ApplicationRepresentation {
protected String id;
protected String name;
protected String adminUrl;
protected String baseUrl;
protected boolean surrogateAuthRequired;
protected boolean useRealmMappings;
protected boolean enabled;
@ -113,6 +114,14 @@ public class ApplicationRepresentation {
this.adminUrl = adminUrl;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public List<CredentialRepresentation> getCredentials() {
return credentials;
}

View file

@ -156,6 +156,17 @@ module.config([ '$routeProvider', function($routeProvider) {
}
},
controller : 'ApplicationRoleDetailCtrl'
}).when('/realms/:realm/applications/:application/credentials', {
templateUrl : 'partials/application-credentials.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function(ApplicationLoader) {
return ApplicationLoader();
}
},
controller : 'ApplicationCredentialsCtrl'
}).when('/realms/:realm/applications/:application/roles', {
templateUrl : 'partials/application-role-list.html',
resolve : {

View file

@ -42,9 +42,6 @@ module.controller('RealmListCtrl', function($scope, Realm, Current) {
module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $location) {
// Current.realms = Realm.get();
$scope.current = Current;
if (Current.realms.length > 0) {
console.log('[0]: ' + current.realms[0].realm);
}
$scope.changeRealm = function() {
$location.url("/realms/" + $scope.current.realm.id);
};
@ -478,6 +475,92 @@ module.controller('ApplicationRoleListCtrl', function($scope, $location, realm,
});
});
function randomString(len) {
var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var randomString = '';
for (var i = 0; i < len; i++) {
var randomPoz = Math.floor(Math.random() * charSet.length);
randomString += charSet.substring(randomPoz,randomPoz+1);
}
return randomString;
}
module.controller('ApplicationCredentialsCtrl', function($scope, $location, realm, application, ApplicationCredentials, Notifications) {
$scope.realm = realm;
$scope.application = application;
var required = realm.requiredApplicationCredentials;
for (var i = 0; i < required.length; i++) {
if (required[i] == 'password') {
$scope.passwordRequired = true;
} else if (required[i] == 'totp') {
$scope.totpRequired = true;
} else if (required[i] == 'cert') {
$scope.certRequired = true;
}
}
$scope.generateTotp = function() {
$scope.totp = randomString(5) + '-' + randomString(5) + '-' + randomString(5);
}
$scope.changePassword = function() {
if ($scope.password != $scope.confirmPassword) {
Notifications.error("Password not confirmed");
$scope.password = "";
$scope.confirmPassword = "";
return;
}
var creds = [
{
type : "password",
value : $scope.password
}
];
ApplicationCredentials.update({ realm : realm.id, application : application.id }, creds,
function() {
Notifications.success('Change password successful');
$scope.password = null;
$scope.confirmPassword = null;
},
function() {
Notifications.error("Change password failed");
$scope.password = null;
$scope.confirmPassword = null;
}
);
};
$scope.changeTotp = function() {
var creds = [
{
type : "totp",
value : $scope.totp
}
];
ApplicationCredentials.update({ realm : realm.id, application : application.id }, creds,
function() {
Notifications.success('Change totp successful');
$scope.totp = null;
},
function() {
Notifications.error("Change totp failed");
$scope.totp = null;
}
);
};
$scope.$watch(function() {
return $location.path();
}, function() {
$scope.path = $location.path().substring(1).split("/");
});
});
module.controller('ApplicationRoleDetailCtrl', function($scope, realm, application, role, ApplicationRole, $location, Dialog, Notifications) {

View file

@ -111,6 +111,8 @@ module.factory('RealmRoleMapping', function($resource) {
});
});
module.factory('ApplicationRoleMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
realm : '@realm',
@ -164,6 +166,19 @@ module.factory('Application', function($resource) {
});
});
module.factory('ApplicationCredentials', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/credentials', {
realm : '@realm',
application : '@application'
}, {
update : {
method : 'PUT',
isArray : true
}
});
});
module.factory('Current', function($resource) {
return {

View file

@ -0,0 +1,64 @@
<div id="wrapper" class="container">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/create/application/{{realm.id}}">New Application</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#">Scope</a></li>
<li><a href="#">Sessions</a></li>
</ul>
</div>
<div id="content">
<h2 class="pull-left" data-ng-hide="create">Application <span>{{application.name}}</span> Credentials</h2>
<p class="subtitle"></p>
<form name="credentialForm" novalidate >
<fieldset data-ng-show="passwordRequired">
<legend uncollapsed><span class="text">Change Password</span></legend>
<div class="form-group">
<label for="password">New Password</label>
<div class="controls">
<input type="password" id="password" name="password" data-ng-model="password" autofocus
required>
</div>
</div>
<div class="form-group">
<label for="password">Confirm New Password</label>
<div class="controls">
<input type="password" id="confirmPassword" name="confirmPassword" data-ng-model="confirmPassword" autofocus
required>
</div>
</div>
<div class="form-group">
<button type="submit" data-ng-click="changePassword()" class="primary" ng-show="password != null">Save
</button>
</div>
</fieldset>
<fieldset data-ng-show="totpRequired">
<legend uncollapsed><span class="text">Change TOTP Key</span></legend>
<div class="form-group">
<label for="totp">New Key</label>
<div class="controls">
<input type="text" id="totp" name="totp" data-ng-model="totp" autofocus
required>
<button type="submit" data-ng-click="generateTotp()">Generate
</button>
</div>
</div>
<div class="form-group">
<label></label>
<button type="submit" data-ng-click="changeTotp()" class="primary" ng-show="totp != null">Save
</button>
</div>
</fieldset>
</form>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>

View file

@ -7,7 +7,7 @@
<li><a href="#/create/application/{{realm.id}}">New Application</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#">Scope</a></li>
@ -49,6 +49,14 @@
</label>
</div>
</div>
<div class="form-group">
<label for="adminUrl" class="control-label">Base URL</label>
<div class="controls">
<input class="input-small" type="text" name="baseUrl" id="baseUrl"
data-ng-model="application.baseUrl">
</div>
</div>
<div class="form-group">
<label for="adminUrl" class="control-label">Admin URL</label>

View file

@ -8,9 +8,9 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public interface ApplicationModel {
void updateResource();
void updateApplication();
UserModel getResourceUser();
UserModel getApplicationUser();
String getId();
@ -30,6 +30,10 @@ public interface ApplicationModel {
void setManagementUrl(String url);
String getBaseUrl();
void setBaseUrl(String url);
RoleModel getRole(String name);
RoleModel addRole(String name);
@ -38,11 +42,11 @@ public interface ApplicationModel {
Set<String> getRoleMappingValues(UserModel user);
void addScope(UserModel agent, String roleName);
void addScopeMapping(UserModel agent, String roleName);
void addScope(UserModel agent, RoleModel role);
void addScopeMapping(UserModel agent, RoleModel role);
Set<String> getScope(UserModel agent);
Set<String> getScopeMapping(UserModel agent);
List<RoleModel> getRoleMappings(UserModel user);

View file

@ -0,0 +1,17 @@
package org.keycloak.models;
import org.keycloak.models.UserModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface OAuthClientModel {
String getId();
UserModel getOAuthAgent();
String getBaseUrl();
void setBaseUrl(String base);
}

View file

@ -97,7 +97,7 @@ public interface RealmModel {
void updateDefaultRoles(String[] defaultRoles);
Map<String, ApplicationModel> getResourceNameMap();
Map<String, ApplicationModel> getApplicationNameMap();
List<ApplicationModel> getApplications();
@ -109,9 +109,9 @@ public interface RealmModel {
Set<String> getRoleMappingValues(UserModel user);
void addScope(UserModel agent, String roleName);
void addScopeMapping(UserModel agent, String roleName);
Set<String> getScope(UserModel agent);
Set<String> getScopeMapping(UserModel agent);
boolean isRealmAdmin(UserModel agent);
@ -160,4 +160,8 @@ public interface RealmModel {
List<RoleModel> getRoleMappings(UserModel user);
void deleteRoleMapping(UserModel user, RoleModel role);
OAuthClientModel addOAuthClient(String name);
OAuthClientModel getOAuthClient(String name);
}

View file

@ -25,20 +25,20 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class ApplicationAdapter implements ApplicationModel {
protected ApplicationData resource;
protected ApplicationData applicationData;
protected RealmAdapter realm;
protected IdentityManager idm;
protected PartitionManager partitionManager;
protected RelationshipManager relationshipManager;
public ApplicationAdapter(ApplicationData resource, RealmAdapter realm, PartitionManager partitionManager) {
this.resource = resource;
public ApplicationAdapter(ApplicationData applicationData, RealmAdapter realm, PartitionManager partitionManager) {
this.applicationData = applicationData;
this.realm = realm;
this.partitionManager = partitionManager;
}
protected IdentityManager getIdm() {
if (idm == null) idm = partitionManager.createIdentityManager(resource);
if (idm == null) idm = partitionManager.createIdentityManager(applicationData);
return idm;
}
@ -48,59 +48,69 @@ public class ApplicationAdapter implements ApplicationModel {
}
@Override
public void updateResource() {
partitionManager.update(resource);
public void updateApplication() {
partitionManager.update(applicationData);
}
@Override
public UserAdapter getResourceUser() {
return new UserAdapter(resource.getResourceUser(), realm.getIdm());
public UserAdapter getApplicationUser() {
return new UserAdapter(applicationData.getResourceUser(), realm.getIdm());
}
@Override
public String getId() {
// for some reason picketlink queries by name when finding partition, don't know what ID is used for now
return resource.getName();
return applicationData.getName();
}
@Override
public String getName() {
return resource.getResourceName();
return applicationData.getResourceName();
}
@Override
public void setName(String name) {
resource.setResourceName(name);
applicationData.setResourceName(name);
}
@Override
public boolean isEnabled() {
return resource.isEnabled();
return applicationData.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
resource.setEnabled(enabled);
applicationData.setEnabled(enabled);
}
@Override
public boolean isSurrogateAuthRequired() {
return resource.isSurrogateAuthRequired();
return applicationData.isSurrogateAuthRequired();
}
@Override
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
resource.setSurrogateAuthRequired(surrogateAuthRequired);
applicationData.setSurrogateAuthRequired(surrogateAuthRequired);
}
@Override
public String getManagementUrl() {
return resource.getManagementUrl();
return applicationData.getManagementUrl();
}
@Override
public void setManagementUrl(String url) {
resource.setManagementUrl(url);
applicationData.setManagementUrl(url);
}
@Override
public String getBaseUrl() {
return applicationData.getBaseUrl();
}
@Override
public void setBaseUrl(String url) {
applicationData.setBaseUrl(url);
}
@Override
@ -136,7 +146,7 @@ public class ApplicationAdapter implements ApplicationModel {
@Override
public List<RoleModel> getRoles() {
IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
query.setParameter(Role.PARTITION, resource);
query.setParameter(Role.PARTITION, applicationData);
List<Role> roles = query.getResultList();
List<RoleModel> roleModels = new ArrayList<RoleModel>();
for (Role role : roles) {
@ -152,7 +162,7 @@ public class ApplicationAdapter implements ApplicationModel {
List<Grant> grants = query.getResultList();
HashSet<String> set = new HashSet<String>();
for (Grant grant : grants) {
if (grant.getRole().getPartition().getId().equals(resource.getId())) set.add(grant.getRole().getName());
if (grant.getRole().getPartition().getId().equals(applicationData.getId())) set.add(grant.getRole().getName());
}
return set;
}
@ -164,7 +174,7 @@ public class ApplicationAdapter implements ApplicationModel {
List<Grant> grants = query.getResultList();
List<RoleModel> set = new ArrayList<RoleModel>();
for (Grant grant : grants) {
if (grant.getRole().getPartition().getId().equals(resource.getId())) set.add(new RoleAdapter(grant.getRole(), getIdm()));
if (grant.getRole().getPartition().getId().equals(applicationData.getId())) set.add(new RoleAdapter(grant.getRole(), getIdm()));
}
return set;
}
@ -184,16 +194,16 @@ public class ApplicationAdapter implements ApplicationModel {
@Override
public void addScope(UserModel agent, String roleName) {
public void addScopeMapping(UserModel agent, String roleName) {
IdentityManager idm = getIdm();
Role role = SampleModel.getRole(idm,roleName);
if (role == null) throw new RuntimeException("role not found");
addScope(agent, new RoleAdapter(role, idm));
addScopeMapping(agent, new RoleAdapter(role, idm));
}
@Override
public void addScope(UserModel agent, RoleModel role) {
public void addScopeMapping(UserModel agent, RoleModel role) {
ScopeRelationship scope = new ScopeRelationship();
scope.setClient(((UserAdapter)agent).getUser());
scope.setScope(((RoleAdapter)role).getRole());
@ -201,13 +211,13 @@ public class ApplicationAdapter implements ApplicationModel {
}
@Override
public Set<String> getScope(UserModel agent) {
public Set<String> getScopeMapping(UserModel agent) {
RelationshipQuery<ScopeRelationship> query = getRelationshipManager().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, ((UserAdapter)agent).getUser());
List<ScopeRelationship> scope = query.getResultList();
HashSet<String> set = new HashSet<String>();
for (ScopeRelationship rel : scope) {
if (rel.getScope().getPartition().getId().equals(resource.getId())) set.add(rel.getScope().getName());
if (rel.getScope().getPartition().getId().equals(applicationData.getId())) set.add(rel.getScope().getName());
}
return set;
}

View file

@ -0,0 +1,44 @@
package org.keycloak.models.picketlink;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.picketlink.relationships.OAuthClientRelationship;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.RelationshipManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OAuthClientAdapter implements OAuthClientModel {
protected OAuthClientRelationship delegate;
protected IdentityManager idm;
protected RelationshipManager relationshipManager;
public OAuthClientAdapter(OAuthClientRelationship delegate, IdentityManager idm, RelationshipManager relationshipManager) {
this.delegate = delegate;
this.idm = idm;
this.relationshipManager = relationshipManager;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public UserModel getOAuthAgent() {
return new UserAdapter(delegate.getOauthAgent(), idm);
}
@Override
public String getBaseUrl() {
return delegate.getBaseUrl();
}
@Override
public void setBaseUrl(String base) {
delegate.setBaseUrl(base);
relationshipManager.update(delegate);
}
}

View file

@ -553,7 +553,7 @@ public class RealmAdapter implements RealmModel {
* @return
*/
@Override
public Map<String, ApplicationModel> getResourceNameMap() {
public Map<String, ApplicationModel> getApplicationNameMap() {
Map<String, ApplicationModel> resourceMap = new HashMap<String, ApplicationModel>();
for (ApplicationModel resource : getApplications()) {
resourceMap.put(resource.getName(), resource);
@ -568,10 +568,10 @@ public class RealmAdapter implements RealmModel {
*/
@Override
public ApplicationModel getApplicationById(String id) {
RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class);
query.setParameter(ResourceRelationship.REALM, realm.getName());
query.setParameter(ResourceRelationship.RESOURCE, id);
List<ResourceRelationship> results = query.getResultList();
RelationshipQuery<ApplicationRelationship> query = getRelationshipManager().createRelationshipQuery(ApplicationRelationship.class);
query.setParameter(ApplicationRelationship.REALM, realm.getName());
query.setParameter(ApplicationRelationship.APPLICATION, id);
List<ApplicationRelationship> results = query.getResultList();
if (results.size() == 0) return null;
ApplicationData resource = partitionManager.getPartition(ApplicationData.class, id);
ApplicationModel model = new ApplicationAdapter(resource, this, partitionManager);
@ -581,12 +581,12 @@ public class RealmAdapter implements RealmModel {
@Override
public List<ApplicationModel> getApplications() {
RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class);
query.setParameter(ResourceRelationship.REALM, realm.getName());
List<ResourceRelationship> results = query.getResultList();
RelationshipQuery<ApplicationRelationship> query = getRelationshipManager().createRelationshipQuery(ApplicationRelationship.class);
query.setParameter(ApplicationRelationship.REALM, realm.getName());
List<ApplicationRelationship> results = query.getResultList();
List<ApplicationModel> resources = new ArrayList<ApplicationModel>();
for (ResourceRelationship relationship : results) {
ApplicationData resource = partitionManager.getPartition(ApplicationData.class, relationship.getResource());
for (ApplicationRelationship relationship : results) {
ApplicationData resource = partitionManager.getPartition(ApplicationData.class, relationship.getApplication());
ApplicationModel model = new ApplicationAdapter(resource, this, partitionManager);
resources.add(model);
}
@ -603,13 +603,13 @@ public class RealmAdapter implements RealmModel {
applicationData.setResourceName(name);
applicationData.setResourceUser(resourceUser);
partitionManager.add(applicationData);
ResourceRelationship resourceRelationship = new ResourceRelationship();
ApplicationRelationship resourceRelationship = new ApplicationRelationship();
resourceRelationship.setRealm(realm.getName());
resourceRelationship.setResource(applicationData.getName());
resourceRelationship.setApplication(applicationData.getName());
getRelationshipManager().add(resourceRelationship);
ApplicationModel resource = new ApplicationAdapter(applicationData, this, partitionManager);
resource.addRole("*");
resource.addScope(new UserAdapter(resourceUser, idm), "*");
resource.addScopeMapping(new UserAdapter(resourceUser, idm), "*");
return resource;
}
@ -667,7 +667,7 @@ public class RealmAdapter implements RealmModel {
@Override
public void addScope(UserModel agent, String roleName) {
public void addScopeMapping(UserModel agent, String roleName) {
IdentityManager idm = getIdm();
Role role = SampleModel.getRole(idm, roleName);
if (role == null) throw new RuntimeException("role not found");
@ -677,9 +677,31 @@ public class RealmAdapter implements RealmModel {
getRelationshipManager().add(scope);
}
@Override
public OAuthClientModel addOAuthClient(String name) {
User client = new User(name);
getIdm().add(client);
OAuthClientRelationship rel = new OAuthClientRelationship();
rel.setOauthAgent(client);
rel.setRealm(realm.getName());
getRelationshipManager().add(rel);
return new OAuthClientAdapter(rel, getIdm(), getRelationshipManager());
}
@Override
public Set<String> getScope(UserModel agent) {
public OAuthClientModel getOAuthClient(String name) {
User user = findPicketlinkUser(name);
if (user == null) return null;
RelationshipQuery<OAuthClientRelationship> query = getRelationshipManager().createRelationshipQuery(OAuthClientRelationship.class);
query.setParameter(OAuthClientRelationship.OAUTH_AGENT, user);
List<OAuthClientRelationship> results = query.getResultList();
if (results.size() == 0) return null;
return new OAuthClientAdapter(results.get(0), getIdm(), getRelationshipManager());
}
@Override
public Set<String> getScopeMapping(UserModel agent) {
RelationshipQuery<ScopeRelationship> query = getRelationshipManager().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, ((UserAdapter)agent).getUser());
List<ScopeRelationship> scope = query.getResultList();

View file

@ -13,6 +13,7 @@ public class ApplicationData extends AbstractPartition {
private boolean enabled;
private boolean surrogateAuthRequired;
private String managementUrl;
private String baseUrl;
private User resourceUser;
public ApplicationData() {
@ -65,4 +66,14 @@ public class ApplicationData extends AbstractPartition {
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
@AttributeProperty
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
}

View file

@ -31,6 +31,8 @@ public class ApplicationEntity implements Serializable {
private boolean surrogateAuthRequired;
@AttributeValue
private String managementUrl;
@AttributeValue
private String baseUrl;
@OneToOne
@AttributeValue
@ -77,6 +79,14 @@ public class ApplicationEntity implements Serializable {
this.managementUrl = managementUrl;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public AccountTypeEntity getResourceUser() {
return resourceUser;
}

View file

@ -10,13 +10,13 @@ import org.picketlink.idm.query.AttributeParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceRelationship extends AbstractAttributedType implements Relationship {
public class ApplicationRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final AttributeParameter REALM = new AttributeParameter("realm");
public static final AttributeParameter RESOURCE = new AttributeParameter("resource");
public static final AttributeParameter APPLICATION = new AttributeParameter("application");
public ResourceRelationship() {
public ApplicationRelationship() {
}
@AttributeProperty
@ -30,12 +30,12 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
@AttributeProperty
public String getResource() {
return (String)getAttribute("resource").getValue();
public String getApplication() {
return (String)getAttribute("application").getValue();
}
public void setResource(String realm) {
setAttribute(new Attribute<String>("resource", realm));
public void setApplication(String app) {
setAttribute(new Attribute<String>("application", app));
}
}

View file

@ -0,0 +1,57 @@
package org.keycloak.models.picketlink.relationships;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OAuthClientRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final AttributeParameter REALM = new AttributeParameter("realm");
public static final RelationshipQueryParameter OAUTH_AGENT = new RelationshipQueryParameter() {
@Override
public String getName() {
return "oauthAgent";
}
};
protected User oauthAgent;
public OAuthClientRelationship() {
}
public String getRealm() {
return (String)getAttribute("realm").getValue();
}
public void setRealm(String realm) {
setAttribute(new Attribute<String>("realm", realm));
}
public User getOauthAgent() {
return oauthAgent;
}
public void setOauthAgent(User oauthAgent) {
this.oauthAgent = oauthAgent;
}
@AttributeProperty
public String getBaseUrl() {
return (String)getAttribute("baseUrl").getValue();
}
public void setBaseUrl(String base) {
setAttribute(new Attribute<String>("baseUrl", base));
}
}

View file

@ -7,22 +7,23 @@ import org.keycloak.representations.idm.*;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceManager {
public class ApplicationManager {
protected RealmManager realmManager;
public ResourceManager(RealmManager realmManager) {
public ApplicationManager(RealmManager realmManager) {
this.realmManager = realmManager;
}
public ApplicationModel createResource(RealmModel realm, RoleModel loginRole, ApplicationRepresentation resourceRep) {
ApplicationModel resource = realm.addApplication(resourceRep.getName());
resource.setEnabled(resourceRep.isEnabled());
resource.setManagementUrl(resourceRep.getAdminUrl());
resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
resource.updateResource();
public ApplicationModel createApplication(RealmModel realm, RoleModel loginRole, ApplicationRepresentation resourceRep) {
ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
applicationModel.setEnabled(resourceRep.isEnabled());
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
applicationModel.setBaseUrl(resourceRep.getBaseUrl());
applicationModel.updateApplication();
UserModel resourceUser = resource.getResourceUser();
UserModel resourceUser = applicationModel.getApplicationUser();
if (resourceRep.getCredentials() != null) {
for (CredentialRepresentation cred : resourceRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel();
@ -36,7 +37,7 @@ public class ResourceManager {
if (resourceRep.getRoles() != null) {
for (RoleRepresentation roleRep : resourceRep.getRoles()) {
RoleModel role = resource.addRole(roleRep.getName());
RoleModel role = applicationModel.addRole(roleRep.getName());
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
}
}
@ -44,9 +45,9 @@ public class ResourceManager {
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
UserModel user = realm.getUser(mapping.getUsername());
for (String roleString : mapping.getRoles()) {
RoleModel role = resource.getRole(roleString.trim());
RoleModel role = applicationModel.getRole(roleString.trim());
if (role == null) {
role = resource.addRole(roleString.trim());
role = applicationModel.addRole(roleString.trim());
}
realm.grantRole(user, role);
}
@ -56,29 +57,30 @@ public class ResourceManager {
for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) {
UserModel user = realm.getUser(mapping.getUsername());
for (String roleString : mapping.getRoles()) {
RoleModel role = resource.getRole(roleString.trim());
RoleModel role = applicationModel.getRole(roleString.trim());
if (role == null) {
role = resource.addRole(roleString.trim());
role = applicationModel.addRole(roleString.trim());
}
resource.addScope(user, role.getName());
applicationModel.addScopeMapping(user, role.getName());
}
}
}
if (resourceRep.isUseRealmMappings()) realm.addScope(resource.getResourceUser(), "*");
return resource;
if (resourceRep.isUseRealmMappings()) realm.addScopeMapping(applicationModel.getApplicationUser(), "*");
return applicationModel;
}
public ApplicationModel createResource(RealmModel realm, ApplicationRepresentation resourceRep) {
RoleModel loginRole = realm.getRole(RealmManager.RESOURCE_ROLE);
return createResource(realm, loginRole, resourceRep);
public ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
RoleModel loginRole = realm.getRole(RealmManager.APPLICATION_ROLE);
return createApplication(realm, loginRole, resourceRep);
}
public void updateResource(ApplicationRepresentation rep, ApplicationModel resource) {
public void updateApplication(ApplicationRepresentation rep, ApplicationModel resource) {
resource.setName(rep.getName());
resource.setEnabled(rep.isEnabled());
resource.setManagementUrl(rep.getAdminUrl());
resource.setBaseUrl(rep.getBaseUrl());
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
resource.updateResource();
resource.updateApplication();
}
@ -89,6 +91,7 @@ public class ResourceManager {
rep.setEnabled(applicationModel.isEnabled());
rep.setAdminUrl(applicationModel.getManagementUrl());
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
rep.setBaseUrl(applicationModel.getBaseUrl());
return rep;
}

View file

@ -211,7 +211,7 @@ public class AuthenticationManager {
Set<String> types = new HashSet<String>();
List<RequiredCredentialModel> requiredCredentials = null;
if (realm.hasRole(user, RealmManager.RESOURCE_ROLE)) {
if (realm.hasRole(user, RealmManager.APPLICATION_ROLE)) {
requiredCredentials = realm.getRequiredApplicationCredentials();
} else if (realm.hasRole(user, RealmManager.IDENTITY_REQUESTER_ROLE)) {
requiredCredentials = realm.getRequiredOAuthClientCredentials();

View file

@ -0,0 +1,24 @@
package org.keycloak.services.managers;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OAuthClientManager {
protected RealmModel realm;
public OAuthClientManager(RealmModel realm) {
this.realm = realm;
}
public OAuthClientModel createOAuthClient(String name) {
OAuthClientModel model = realm.addOAuthClient(name);
RoleModel role = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
realm.grantRole(model.getOAuthAgent(), role);
return model;
}
}

View file

@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicLong;
public class RealmManager {
protected static final Logger logger = Logger.getLogger(RealmManager.class);
private static AtomicLong counter = new AtomicLong(1);
public static final String RESOURCE_ROLE = "KEYCLOAK_RESOURCE";
public static final String APPLICATION_ROLE = "KEYCLOAK_APPLICATION";
public static final String IDENTITY_REQUESTER_ROLE = "KEYCLOAK_IDENTITY_REQUESTER";
public static final String WILDCARD_ROLE = "*";
@ -50,7 +50,7 @@ public class RealmManager {
RealmModel realm = identitySession.createRealm(id, name);
realm.setName(name);
realm.addRole(WILDCARD_ROLE);
realm.addRole(RESOURCE_ROLE);
realm.addRole(APPLICATION_ROLE);
realm.addRole(IDENTITY_REQUESTER_ROLE);
return realm;
}
@ -74,10 +74,12 @@ public class RealmManager {
if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
if (rep.isAutomaticRegistrationAfterSocialLogin() != null) realm.setAutomaticRegistrationAfterSocialLogin(rep.isAutomaticRegistrationAfterSocialLogin());
if (rep.isAutomaticRegistrationAfterSocialLogin() != null)
realm.setAutomaticRegistrationAfterSocialLogin(rep.isAutomaticRegistrationAfterSocialLogin());
if (rep.isSslNotRequired() != null) realm.setSslNotRequired((rep.isSslNotRequired()));
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
if (rep.getAccessCodeLifespanUserAction() != null) realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
if (rep.getAccessCodeLifespanUserAction() != null)
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
if (rep.getTokenLifespan() != null) realm.setTokenLifespan(rep.getTokenLifespan());
if (rep.getRequiredOAuthClientCredentials() != null) {
realm.updateRequiredOAuthClientCredentials(rep.getRequiredOAuthClientCredentials());
@ -113,7 +115,8 @@ public class RealmManager {
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
else newRealm.setAccessCodeLifespan(60);
if (rep.getAccessCodeLifespanUserAction() != null) newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
if (rep.getAccessCodeLifespanUserAction() != null)
newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
else newRealm.setAccessCodeLifespanUserAction(300);
if (rep.isSslNotRequired() != null) newRealm.setSslNotRequired(rep.isSslNotRequired());
@ -121,7 +124,8 @@ public class RealmManager {
if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
if (rep.isAutomaticRegistrationAfterSocialLogin() != null) newRealm.setAutomaticRegistrationAfterSocialLogin(rep.isAutomaticRegistrationAfterSocialLogin());
if (rep.isAutomaticRegistrationAfterSocialLogin() != null)
newRealm.setAutomaticRegistrationAfterSocialLogin(rep.isAutomaticRegistrationAfterSocialLogin());
if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
generateRealmKeys(newRealm);
} else {
@ -175,7 +179,7 @@ public class RealmManager {
}
if (rep.getApplications() != null) {
createResources(rep, newRealm);
createApplications(rep, newRealm);
}
if (rep.getRoleMappings() != null) {
@ -199,7 +203,7 @@ public class RealmManager {
role = newRealm.addRole(roleString.trim());
}
UserModel user = userMap.get(scope.getUsername());
newRealm.addScope(user, role.getName());
newRealm.addScopeMapping(user, role.getName());
}
}
@ -237,18 +241,23 @@ public class RealmManager {
}
if (userRep.getCredentials() != null) {
for (CredentialRepresentation cred : userRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
UserCredentialModel credential = fromRepresentation(cred);
newRealm.updateCredential(user, credential);
}
}
return user;
}
public static UserCredentialModel fromRepresentation(CredentialRepresentation cred) {
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
return credential;
}
/**
* Query users based on a search string:
*
* <p/>
* "Bill Burke" first and last name
* "bburke@redhat.com" email
* "Burke" lastname or username
@ -291,7 +300,7 @@ public class RealmManager {
List<UserModel> results = new ArrayList<UserModel>();
results.addAll(usernameQuery);
for (UserModel lastnameUser : lastnameQuery) {
boolean found = false;
boolean found = false;
for (UserModel usernameUser : usernameQuery) {
if (usernameUser.getLoginName().equals(lastnameUser.getLoginName())) {
found = true;
@ -309,20 +318,21 @@ public class RealmManager {
public void addRequiredCredential(RealmModel newRealm, String requiredCred) {
newRealm.addRequiredCredential(requiredCred);
}
public void addResourceRequiredCredential(RealmModel newRealm, String requiredCred) {
newRealm.addRequiredResourceCredential(requiredCred);
}
public void addOAuthClientRequiredCredential(RealmModel newRealm, String requiredCred) {
newRealm.addRequiredOAuthClientCredential(requiredCred);
}
protected void createResources(RealmRepresentation rep, RealmModel realm) {
RoleModel loginRole = realm.getRole(RealmManager.RESOURCE_ROLE);
ResourceManager manager = new ResourceManager(this);
protected void createApplications(RealmRepresentation rep, RealmModel realm) {
RoleModel loginRole = realm.getRole(RealmManager.APPLICATION_ROLE);
ApplicationManager manager = new ApplicationManager(this);
for (ApplicationRepresentation resourceRep : rep.getApplications()) {
manager.createResource(realm, loginRole, resourceRep);
manager.createApplication(realm, loginRole, resourceRep);
}
}

View file

@ -50,7 +50,7 @@ public class TokenManager {
Set<String> realmMapping = realm.getRoleMappingValues(user);
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
Set<String> scope = realm.getScope(client);
Set<String> scope = realm.getScopeMapping(client);
if (scope.size() > 0) {
Set<String> scopeRequest = null;
if (scopeMap != null) {
@ -69,7 +69,7 @@ public class TokenManager {
for (ApplicationModel resource : realm.getApplications()) {
Set<String> mapping = resource.getRoleMappingValues(user);
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
Set<String> scope = resource.getScope(client);
Set<String> scope = resource.getScopeMapping(client);
if (scope.size() > 0) {
Set<String> scopeRequest = null;
if (scopeMap != null) {
@ -131,7 +131,7 @@ public class TokenManager {
}
if (accessCodeEntry.getResourceRolesRequested().size() > 0) {
Map<String, ApplicationModel> resourceMap = realm.getResourceNameMap();
Map<String, ApplicationModel> resourceMap = realm.getApplicationNameMap();
for (String resourceName : accessCodeEntry.getResourceRolesRequested().keySet()) {
ApplicationModel resource = resourceMap.get(resourceName);
SkeletonKeyToken.Access access = token.addAccess(resourceName).verifyCaller(resource.isSurrogateAuthRequired());

View file

@ -451,7 +451,7 @@ public class TokenService {
return null;
}
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
RoleModel resourceRole = realm.getRole(RealmManager.APPLICATION_ROLE);
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) {

View file

@ -4,9 +4,10 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.models.*;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceManager;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
@ -38,17 +39,17 @@ public class ApplicationResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void update(final ApplicationRepresentation rep) {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
resourceManager.updateResource(rep, application);
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
applicationManager.updateApplication(rep, application);
}
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public ApplicationRepresentation getResource(final @PathParam("id") String id) {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
return resourceManager.toRepresentation(application);
public ApplicationRepresentation getApplication() {
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
return applicationManager.toRepresentation(application);
}
@Path("roles")
@ -104,4 +105,18 @@ public class ApplicationResource {
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getId()).build()).build();
}
@Path("credentials")
@PUT
@Consumes("application/json")
public void updateCredentials(List<CredentialRepresentation> credentials) {
logger.info("updateCredentials");
if (credentials == null) return;
for (CredentialRepresentation rep : credentials) {
UserCredentialModel cred = RealmManager.fromRepresentation(rep);
realm.updateCredential(application.getApplicationUser(), cred);
}
}
}

View file

@ -3,8 +3,8 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceManager;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -45,7 +45,7 @@ public class ApplicationsResource {
public List<ApplicationRepresentation> getResources() {
List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>();
List<ApplicationModel> applicationModels = realm.getApplications();
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
for (ApplicationModel applicationModel : applicationModels) {
rep.add(resourceManager.toRepresentation(applicationModel));
}
@ -55,8 +55,8 @@ public class ApplicationsResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createResource(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
ApplicationModel applicationModel = resourceManager.createResource(realm, rep);
ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
ApplicationModel applicationModel = resourceManager.createApplication(realm, rep);
return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getId()).build()).build();
}

View file

@ -322,4 +322,22 @@ public class UsersResource {
}
}
}
@Path("{username}/credentials")
@PUT
@Consumes("application/json")
public void updateCredentials(@PathParam("username") String username, List<CredentialRepresentation> credentials) {
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
}
if (credentials == null) return;
for (CredentialRepresentation rep : credentials) {
UserCredentialModel cred = RealmManager.fromRepresentation(rep);
realm.updateCredential(user, cred);
}
}
}

View file

@ -81,7 +81,7 @@ public class OAuthFlows {
}
public Response processAccessCode(String scopeParam, String state, String redirect, UserModel client, UserModel user) {
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
RoleModel resourceRole = realm.getRole(RealmManager.APPLICATION_ROLE);
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) {

View file

@ -6,15 +6,10 @@ import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.keycloak.models.*;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.services.resources.KeycloakApplication;
@ -135,6 +130,19 @@ public class AdapterTest {
Assert.assertTrue(realmModel.validatePassword(user, "geheim"));
}
@Test
public void testOAuthClient() throws Exception {
test1CreateRealm();
OAuthClientModel oauth = new OAuthClientManager(realmModel).createOAuthClient("oauth-client");
oauth.setBaseUrl("/foo/bar");
oauth = realmModel.getOAuthClient("oauth-client");
Assert.assertEquals("/foo/bar", oauth.getBaseUrl());
Assert.assertTrue(realmModel.hasRole(oauth.getOAuthAgent(), RealmManager.IDENTITY_REQUESTER_ROLE));
}
@Test
public void testUserSearch() throws Exception {
test1CreateRealm();

View file

@ -86,7 +86,7 @@ public class ImportTest {
UserModel user = realm.getUser("loginclient");
Assert.assertNotNull(user);
Set<String> scopes = realm.getScope(user);
Set<String> scopes = realm.getScopeMapping(user);
System.out.println("Scopes size: " + scopes.size());
Assert.assertTrue(scopes.contains("*"));
Assert.assertEquals(0, realm.getSocialLinks(user).size());
@ -97,11 +97,11 @@ public class ImportTest {
Assert.assertEquals(1, realms.size());
// Test scope relationship
ApplicationModel application = realm.getResourceNameMap().get("Application");
ApplicationModel application = realm.getApplicationNameMap().get("Application");
UserModel oauthClient = realm.getUser("oauthclient");
Assert.assertNotNull(application);
Assert.assertNotNull(oauthClient);
Set<String> appScopes = application.getScope(oauthClient);
Set<String> appScopes = application.getScopeMapping(oauthClient);
Assert.assertTrue(appScopes.contains("user"));
// Test social linking