Merge pull request #259 from patriot1burke/master

revocation and fix login.ftl
This commit is contained in:
Bill Burke 2014-03-03 16:32:22 -05:00
commit 735486c36e
39 changed files with 399 additions and 57 deletions

View file

@ -319,6 +319,18 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'ApplicationRoleListCtrl'
})
.when('/realms/:realm/applications/:application/revocation', {
templateUrl : 'partials/application-revocation.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function(ApplicationLoader) {
return ApplicationLoader();
}
},
controller : 'ApplicationRevocationCtrl'
})
.when('/realms/:realm/applications/:application/scope-mappings', {
templateUrl : 'partials/application-scope-mappings.html',
resolve : {
@ -409,6 +421,18 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'OAuthClientClaimsCtrl'
})
.when('/realms/:realm/oauth-clients/:oauth/revocation', {
templateUrl : 'partials/oauth-client-revocation.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
oauth : function(OAuthClientLoader) {
return OAuthClientLoader();
}
},
controller : 'OAuthClientRevocationCtrl'
})
.when('/realms/:realm/oauth-clients/:oauth/credentials', {
templateUrl : 'partials/oauth-client-credentials.html',
resolve : {

View file

@ -384,3 +384,49 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
});
module.controller('ApplicationRevocationCtrl', function($scope, realm, application, Application, ApplicationPushRevocation, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.application = application;
var setNotBefore = function() {
if ($scope.application.notBefore == 0) {
$scope.notBefore = "None";
} else {
$scope.notBefore = new Date($scope.application.notBefore * 1000);
}
};
setNotBefore();
var refresh = function() {
Application.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
$scope.application = updated;
setNotBefore();
})
};
$scope.clear = function() {
$scope.application.notBefore = 0;
Application.update({ realm : realm.realm, application: application.name}, $scope.application, function () {
$scope.notBefore = "None";
Notifications.success('Not Before cleared for application.');
refresh();
});
}
$scope.setNotBeforeNow = function() {
$scope.application.notBefore = new Date().getTime()/1000;
Application.update({ realm : realm.realm, application: $scope.application.name}, $scope.application, function () {
Notifications.success('Not Before cleared for application.');
refresh();
});
}
$scope.pushRevocation = function() {
ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.name}, function () {
Notifications.success('Push sent for application.');
});
}
});

View file

@ -287,3 +287,43 @@ module.controller('OAuthClientInstallationCtrl', function($scope, realm, install
$scope.installation = installation;
$scope.download = OAuthClientInstallation.url({ realm: $routeParams.realm, oauth: $routeParams.oauth });
});
module.controller('OAuthClientRevocationCtrl', function($scope, realm, oauth, OAuthClient, $location, Dialog, Notifications) {
$scope.oauth = oauth;
$scope.realm = realm;
var setNotBefore = function() {
if ($scope.oauth.notBefore == 0) {
$scope.notBefore = "None";
} else {
$scope.notBefore = new Date($scope.oauth.notBefore * 1000);
}
};
setNotBefore();
var refresh = function() {
OAuthClient.get({ realm : realm.realm, id: $scope.oauth.id }, function(updated) {
$scope.oauth = updated;
setNotBefore();
})
};
$scope.clear = function() {
$scope.oauth.notBefore = 0;
OAuthClient.update({ realm : realm.realm, id: $scope.oauth.id}, $scope.oauth, function () {
$scope.notBefore = "None";
Notifications.success('Not Before cleared for application.');
refresh();
});
}
$scope.setNotBeforeNow = function() {
$scope.oauth.notBefore = new Date().getTime()/1000;
OAuthClient.update({ realm : realm.realm, id: $scope.oauth.id}, $scope.oauth, function () {
Notifications.success('Not Before cleared for application.');
refresh();
});
}
});

View file

@ -691,7 +691,7 @@ module.controller('RealmKeysDetailCtrl', function($scope, Realm, realm, $http, $
});
module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevocation, realm, $http, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.realm = angular.copy(realm);
var setNotBefore = function() {
if ($scope.realm.notBefore == 0) {
@ -701,29 +701,27 @@ module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevoca
}
};
if (realm.notBefore == 0) {
$scope.notBefore = "None";
} else {
$scope.notBefore = new Date(realm.notBefore);
}
setNotBefore();
var reset = function() {
Realm.get({ id : realm.realm }, function(updated) {
$scope.realm = updated;
setNotBefore();
})
};
$scope.clear = function() {
Realm.update({ realm: realm.realm, notBefore : 0 }, function () {
$scope.notBefore = "None";
Notifications.success('Not Before cleared for realm.');
Realm.get({ id : realm.realm }, function(updated) {
$scope.realm = updated;
setNotBefore();
})
reset();
});
}
$scope.setNotBeforeNow = function() {
Realm.update({ realm: realm.realm, notBefore : new Date().getTime()/1000}, function () {
Notifications.success('Not Before cleared for realm.');
Realm.get({ id : realm.realm }, function(updated) {
$scope.realm = updated;
setNotBefore();
})
reset();
});
}
$scope.pushRevocation = function() {

View file

@ -467,6 +467,14 @@ module.factory('ApplicationClaims', function($resource) {
});
});
module.factory('ApplicationPushRevocation', function($resource) {
return $resource('//auth/rest/admin/realms/:realm/applications/:application/push-revocation', {
realm : '@realm',
application : "@application"
});
});
module.factory('Application', function($resource) {
return $resource('/auth/rest/admin/realms/:realm/applications/:application', {

View file

@ -7,6 +7,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">

View file

@ -7,6 +7,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">

View file

@ -7,6 +7,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">

View file

@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div class="top-nav" data-ng-show="create">

View file

@ -0,0 +1,37 @@
<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">
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/">{{realm.realm}}</a></li>
<li class="active">Revocation</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Revocation Policies</h2>
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
<fieldset class="border-top">
<div class="form-group">
<label class="col-sm-2 control-label" for="notBefore">Not Before</label>
<div class="col-sm-4">
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
</div>
</div>
</fieldset>
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
<button type="submit" data-ng-click="clear()" class="btn btn-default btn-lg">Clear
</button>
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-primary btn-lg">Set To Now
</button>
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary btn-lg">Push
</button>
</div>
</form>
</div>
</div>

View file

@ -7,6 +7,7 @@
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">

View file

@ -8,6 +8,7 @@
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">

View file

@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul>
<div id="content">

View file

@ -6,6 +6,7 @@
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Allowed Claims</h2>

View file

@ -6,6 +6,7 @@
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">

View file

@ -6,6 +6,7 @@
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">

View file

@ -6,6 +6,7 @@
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<h2>OAuth Client Installation</h2>

View file

@ -0,0 +1,36 @@
<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">
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li class="active">Revocation</li>
</ol>
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Revocation Policies</h2>
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
<fieldset class="border-top">
<div class="form-group">
<label class="col-sm-2 control-label" for="notBefore">Not Before</label>
<div class="col-sm-4">
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
</div>
</div>
</fieldset>
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
<button type="submit" data-ng-click="clear()" class="btn btn-default btn-lg">Clear
</button>
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-primary btn-lg">Set To Now
</button>
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary btn-lg">Push
</button>
</div>
</form>
</div>
</div>

View file

@ -7,6 +7,7 @@
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul>
<div id="content">

View file

@ -12,13 +12,15 @@ public class ApplicationRepresentation {
protected String name;
protected String adminUrl;
protected String baseUrl;
protected boolean surrogateAuthRequired;
protected boolean enabled;
protected Boolean surrogateAuthRequired;
protected Boolean enabled;
protected String secret;
protected String[] defaultRoles;
protected List<String> redirectUris;
protected List<String> webOrigins;
protected ClaimRepresentation claims;
protected Integer notBefore;
public String getId() {
return id;
@ -36,19 +38,19 @@ public class ApplicationRepresentation {
this.name = name;
}
public boolean isEnabled() {
public Boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public boolean isSurrogateAuthRequired() {
public Boolean isSurrogateAuthRequired() {
return surrogateAuthRequired;
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
public void setSurrogateAuthRequired(Boolean surrogateAuthRequired) {
this.surrogateAuthRequired = surrogateAuthRequired;
}
@ -107,4 +109,12 @@ public class ApplicationRepresentation {
public void setClaims(ClaimRepresentation claims) {
this.claims = claims;
}
public Integer getNotBefore() {
return notBefore;
}
public void setNotBefore(Integer notBefore) {
this.notBefore = notBefore;
}
}

View file

@ -12,9 +12,11 @@ public class OAuthClientRepresentation {
protected String baseUrl;
protected List<String> redirectUris;
protected List<String> webOrigins;
protected boolean enabled;
protected Boolean enabled;
protected String secret;
protected ClaimRepresentation claims;
protected Integer notBefore;
public String getId() {
return id;
@ -32,11 +34,11 @@ public class OAuthClientRepresentation {
this.name = name;
}
public boolean isEnabled() {
public Boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
@ -79,4 +81,12 @@ public class OAuthClientRepresentation {
public void setClaims(ClaimRepresentation claims) {
this.claims = claims;
}
public Integer getNotBefore() {
return notBefore;
}
public void setNotBefore(Integer notBefore) {
this.notBefore = notBefore;
}
}

View file

@ -1,5 +1,5 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=social.displaySocialProviders; section>
<@layout.registrationLayout displayInfo=social.displayInfo; section>
<#if section = "title">
${rb.loginTitle} ${realm.name}
<#elseif section = "header">
@ -57,6 +57,7 @@
</div>
</#if>
<#if social.providers??>
<div id="kc-social-providers">
<ul>
<#list social.providers as p>
@ -64,5 +65,6 @@
</#list>
</ul>
</div>
</#if>
</#if>
</@layout.registrationLayout>

View file

@ -39,8 +39,10 @@ public class SocialBean {
private boolean displaySocial;
private List<SocialProvider> providers;
private RealmModel realm;
public SocialBean(RealmModel realm, URI baseURI) {
this.realm = realm;
Map<String, String> socialConfig = realm.getSocialConfig();
if (realm.isSocial() && !socialConfig.isEmpty()) {
displaySocial = true;
@ -60,6 +62,10 @@ public class SocialBean {
return providers;
}
public boolean isDisplayInfo() {
return realm.isRegistrationAllowed() || displaySocial;
}
public boolean isDisplaySocialProviders() {
return displaySocial;
}

View file

@ -51,4 +51,14 @@ public interface ClientModel {
public void setSecret(String secret);
RealmModel getRealm();
/**
* Time in seconds since epoc
*
* @return
*/
int getNotBefore();
void setNotBefore(int notBefore);
}

View file

@ -5,5 +5,6 @@ package org.keycloak.models;
* @version $Revision: 1 $
*/
public interface OAuthClientModel extends ClientModel {
void setClientId(String id);
}

View file

@ -119,6 +119,16 @@ public class ClientAdapter implements ClientModel {
return secret.equals(entity.getSecret());
}
@Override
public int getNotBefore() {
return entity.getNotBefore();
}
@Override
public void setNotBefore(int notBefore) {
entity.setNotBefore(notBefore);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -18,5 +18,8 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
super(realm, entity);
}
@Override
public void setClientId(String id) {
entity.setName(id);
}
}

View file

@ -31,6 +31,7 @@ public class ClientEntity {
private boolean enabled;
private String secret;
private long allowedClaimsMask;
private int notBefore;
@ElementCollection
@ -92,4 +93,12 @@ public class ClientEntity {
public void setSecret(String secret) {
this.secret = secret;
}
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
}

View file

@ -113,6 +113,15 @@ public class ApplicationAdapter extends AbstractAdapter implements ApplicationMo
application.setAllowedClaimsMask(mask);
}
@Override
public int getNotBefore() {
return application.getNotBefore();
}
@Override
public void setNotBefore(int notBefore) {
application.setNotBefore(notBefore);
}
@Override
public RoleAdapter getRole(String name) {

View file

@ -37,6 +37,11 @@ public class OAuthClientAdapter extends AbstractAdapter implements OAuthClientMo
return delegate.getName();
}
@Override
public void setClientId(String id) {
delegate.setName(id);
}
@Override
public RealmModel getRealm() {
return realm;
@ -67,6 +72,16 @@ public class OAuthClientAdapter extends AbstractAdapter implements OAuthClientMo
return delegate;
}
@Override
public int getNotBefore() {
return delegate.getNotBefore();
}
@Override
public void setNotBefore(int notBefore) {
delegate.setNotBefore(notBefore);
}
@Override
public Set<String> getWebOrigins() {
Set<String> result = new HashSet<String>();

View file

@ -23,6 +23,7 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
private String managementUrl;
private String baseUrl;
private String secret;
private int notBefore;
private String realmId;
private long allowedClaimsMask;
@ -146,6 +147,15 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
this.defaultRoles = defaultRoles;
}
@MongoField
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
@Override
public void afterRemove(MongoStoreInvocationContext context) {
// Remove all roles, which belongs to this application

View file

@ -19,6 +19,7 @@ public class OAuthClientEntity extends AbstractMongoIdentifiableEntity implement
private String realmId;
private String secret;
private long allowedClaimsMask;
private int notBefore;
private List<String> scopeIds;
private List<String> webOrigins;
private List<String> redirectUris;
@ -96,8 +97,14 @@ public class OAuthClientEntity extends AbstractMongoIdentifiableEntity implement
this.scopeIds = scopeIds;
}
@MongoField
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
@Override
public void afterRemove(MongoStoreInvocationContext context) {

View file

@ -52,12 +52,16 @@ public class ApplicationManager {
public ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
applicationModel.setEnabled(resourceRep.isEnabled());
if (resourceRep.isEnabled() != null) applicationModel.setEnabled(resourceRep.isEnabled());
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
if (resourceRep.isSurrogateAuthRequired() != null) applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
applicationModel.setBaseUrl(resourceRep.getBaseUrl());
applicationModel.updateApplication();
if (resourceRep.getNotBefore() != null) {
applicationModel.setNotBefore(resourceRep.getNotBefore());
}
applicationModel.setSecret(resourceRep.getSecret());
if (applicationModel.getSecret() == null) {
generateSecret(applicationModel);
@ -132,13 +136,16 @@ public class ApplicationManager {
}
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());
if (rep.getName() != null) resource.setName(rep.getName());
if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl());
if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl());
if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
resource.updateApplication();
if (rep.getNotBefore() != null) {
resource.setNotBefore(rep.getNotBefore());
}
if (rep.getDefaultRoles() != null) {
resource.updateDefaultRoles(rep.getDefaultRoles());
}
@ -166,6 +173,7 @@ public class ApplicationManager {
rep.setAdminUrl(applicationModel.getManagementUrl());
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
rep.setBaseUrl(applicationModel.getBaseUrl());
rep.setNotBefore(applicationModel.getNotBefore());
Set<String> redirectUris = applicationModel.getRedirectUris();
if (redirectUris != null) {

View file

@ -52,11 +52,16 @@ public class OAuthClientManager {
if (rep.getClaims() != null) {
ClaimManager.setClaims(model, rep.getClaims());
}
if (rep.getNotBefore() != null) {
model.setNotBefore(rep.getNotBefore());
}
return model;
}
public void update(OAuthClientRepresentation rep, OAuthClientModel model) {
model.setEnabled(rep.isEnabled());
public void update(OAuthClientRepresentation rep, OAuthClientModel model)
{
if (rep.getName() != null) model.setClientId(rep.getName());
if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
List<String> redirectUris = rep.getRedirectUris();
if (redirectUris != null) {
model.setRedirectUris(new HashSet<String>(redirectUris));
@ -70,6 +75,11 @@ public class OAuthClientManager {
if (rep.getClaims() != null) {
ClaimManager.setClaims(model, rep.getClaims());
}
if (rep.getNotBefore() != null) {
model.setNotBefore(rep.getNotBefore());
}
}
public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
@ -86,6 +96,7 @@ public class OAuthClientManager {
if (webOrigins != null) {
rep.setWebOrigins(new LinkedList<String>(webOrigins));
}
rep.setNotBefore(model.getNotBefore());
return rep;
}

View file

@ -106,7 +106,6 @@ public class RealmManager {
public void updateRealm(RealmRepresentation rep, RealmModel realm) {
if (rep.getRealm() != null) {
logger.info("Updating realm name to " + rep.getRealm());
realm.setName(rep.getRealm());
}
if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
@ -128,10 +127,10 @@ public class RealmManager {
if (rep.getRequiredCredentials() != null) {
realm.updateRequiredCredentials(rep.getRequiredCredentials());
}
realm.setLoginTheme(rep.getLoginTheme());
realm.setAccountTheme(rep.getAccountTheme());
if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
if (rep.getDefaultRoles() != null) {
realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
@ -232,8 +231,8 @@ public class RealmManager {
newRealm.setPrivateKeyPem(rep.getPrivateKey());
newRealm.setPublicKeyPem(rep.getPublicKey());
}
newRealm.setLoginTheme(rep.getLoginTheme());
newRealm.setAccountTheme(rep.getAccountTheme());
if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
Map<String, UserModel> userMap = new HashMap<String, UserModel>();
@ -245,7 +244,7 @@ public class RealmManager {
addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
}
newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
if (rep.getUsers() != null) {
for (UserRepresentation userRep : rep.getUsers()) {

View file

@ -54,25 +54,38 @@ public class ResourceAdminManager {
}
}
public void pushRevocationPolicies(RealmModel realm) {
public void pushRealmRevocationPolicy(RealmModel realm) {
ResteasyClient client = new ResteasyClientBuilder()
.disableTrustManager() // todo fix this, should have a trust manager or a good default
.build();
try {
for (ApplicationModel application : realm.getApplications()) {
pushRevocationPolicies(realm, application, client);
pushRevocationPolicy(realm, application, realm.getNotBefore(), client);
}
} finally {
client.close();
}
}
public boolean pushRevocationPolicies(RealmModel realm, ApplicationModel resource, ResteasyClient client) {
public void pushApplicationRevocationPolicy(RealmModel realm, ApplicationModel application) {
ResteasyClient client = new ResteasyClientBuilder()
.disableTrustManager() // todo fix this, should have a trust manager or a good default
.build();
try {
pushRevocationPolicy(realm, application, application.getNotBefore(), client);
} finally {
client.close();
}
}
protected boolean pushRevocationPolicy(RealmModel realm, ApplicationModel resource, int notBefore, ResteasyClient client) {
if (realm.getNotBefore() <= 0) return false;
String managementUrl = resource.getManagementUrl();
if (managementUrl != null) {
PushNotBeforeAction adminAction = new PushNotBeforeAction(TokenIdGenerator.generateId(), (int)(System.currentTimeMillis() / 1000) + 30, resource.getName(), realm.getNotBefore());
PushNotBeforeAction adminAction = new PushNotBeforeAction(TokenIdGenerator.generateId(), (int)(System.currentTimeMillis() / 1000) + 30, resource.getName(), notBefore);
String token = new TokenManager().encodeToken(realm, adminAction);
logger.info("pushRevocation resource: {0} url: {1}", resource.getName(), managementUrl);
Response response = client.target(managementUrl).path(AdapterConstants.K_PUSH_NOT_BEFORE).request().post(Entity.text(token));

View file

@ -146,6 +146,15 @@ public class TokenManager {
}
if (!client.getClientId().equals(refreshToken.getIssuedFor())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
}
if (refreshToken.getIssuedAt() < client.getNotBefore()) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
}
ApplicationModel clientApp = (client instanceof ApplicationModel) ? (ApplicationModel)client : null;
@ -195,13 +204,6 @@ public class TokenManager {
return createClientAccessToken(scopeParam, realm, client, user, new LinkedList<RoleModel>(), new MultivaluedHashMap<String, RoleModel>());
}
protected ClientModel getClaimRequester(RealmModel realm, UserModel client) {
ClientModel model = realm.getApplicationByName(client.getLoginName());
if (model != null) return model;
return realm.getOAuthClient(client.getLoginName());
}
public AccessToken createClientAccessToken(String scopeParam, RealmModel realm, ClientModel client, UserModel user, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested) {
AccessScope scopeMap = null;
if (scopeParam != null) scopeMap = decodeScope(scopeParam);

View file

@ -11,6 +11,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.util.JsonSerialization;
@ -185,6 +186,14 @@ public class ApplicationResource {
}
}
@Path("push-revocation")
@POST
public void pushRevocation() {
auth.requireManage();
new ResourceAdminManager().pushApplicationRevocationPolicy(realm, application);
}
}

View file

@ -2,12 +2,9 @@ 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.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
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.ResourceAdminManager;
@ -112,7 +109,7 @@ public class RealmAdminResource {
@POST
public void pushRevocation() {
auth.requireManage();
new ResourceAdminManager().pushRevocationPolicies(realm);
new ResourceAdminManager().pushRealmRevocationPolicy(realm);
}
}