revocation

This commit is contained in:
Bill Burke 2014-03-03 15:50:10 -05:00
parent 22b25a0d9e
commit 716972347d
37 changed files with 389 additions and 56 deletions

View file

@ -319,6 +319,18 @@ module.config([ '$routeProvider', function($routeProvider) {
}, },
controller : 'ApplicationRoleListCtrl' 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', { .when('/realms/:realm/applications/:application/scope-mappings', {
templateUrl : 'partials/application-scope-mappings.html', templateUrl : 'partials/application-scope-mappings.html',
resolve : { resolve : {
@ -409,6 +421,18 @@ module.config([ '$routeProvider', function($routeProvider) {
}, },
controller : 'OAuthClientClaimsCtrl' 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', { .when('/realms/:realm/oauth-clients/:oauth/credentials', {
templateUrl : 'partials/oauth-client-credentials.html', templateUrl : 'partials/oauth-client-credentials.html',
resolve : { resolve : {

View file

@ -384,3 +384,48 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
}); });
module.controller('ApplicationRevocationCtrl', function($scope, realm, application, Application, ApplicationPushRevocation, $location, Dialog, Notifications) {
$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;
Realm.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.installation = installation;
$scope.download = OAuthClientInstallation.url({ realm: $routeParams.realm, oauth: $routeParams.oauth }); $scope.download = OAuthClientInstallation.url({ realm: $routeParams.realm, oauth: $routeParams.oauth });
}); });
module.controller('OAuthClientRevocationCtrl', function($scope, realm, oauth, OAuthClient, $location, Dialog, Notifications) {
$scope.oauth = oauth;
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) { module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevocation, realm, $http, $location, Dialog, Notifications) {
$scope.realm = realm; $scope.realm = angular.copy(realm);
var setNotBefore = function() { var setNotBefore = function() {
if ($scope.realm.notBefore == 0) { if ($scope.realm.notBefore == 0) {
@ -701,29 +701,27 @@ module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevoca
} }
}; };
if (realm.notBefore == 0) { setNotBefore();
$scope.notBefore = "None";
} else { var reset = function() {
$scope.notBefore = new Date(realm.notBefore); Realm.get({ id : realm.realm }, function(updated) {
} $scope.realm = updated;
setNotBefore();
})
};
$scope.clear = function() { $scope.clear = function() {
Realm.update({ realm: realm.realm, notBefore : 0 }, function () { Realm.update({ realm: realm.realm, notBefore : 0 }, function () {
$scope.notBefore = "None"; $scope.notBefore = "None";
Notifications.success('Not Before cleared for realm.'); Notifications.success('Not Before cleared for realm.');
Realm.get({ id : realm.realm }, function(updated) { reset();
$scope.realm = updated;
setNotBefore();
})
}); });
} }
$scope.setNotBeforeNow = function() { $scope.setNotBeforeNow = function() {
Realm.update({ realm: realm.realm, notBefore : new Date().getTime()/1000}, function () { Realm.update({ realm: realm.realm, notBefore : new Date().getTime()/1000}, function () {
Notifications.success('Not Before cleared for realm.'); Notifications.success('Not Before cleared for realm.');
Realm.get({ id : realm.realm }, function(updated) { reset();
$scope.realm = updated;
setNotBefore();
})
}); });
} }
$scope.pushRevocation = function() { $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) { module.factory('Application', function($resource) {
return $resource('/auth/rest/admin/realms/:realm/applications/:application', { 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><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 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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<ol class="breadcrumb" data-ng-hide="create"> <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}}/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}}/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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<ol class="breadcrumb" data-ng-hide="create"> <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}}/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}}/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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<ol class="breadcrumb" data-ng-show="create"> <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}}/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}}/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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div class="top-nav" data-ng-show="create"> <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 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}}/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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <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 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}}/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}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <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}}/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}}/claims">Claims</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</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> </ul>
<div id="content"> <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 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}}/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}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Allowed Claims</h2> <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}}/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}}/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}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <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}}/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}}/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}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<ol class="breadcrumb" data-ng-show="create"> <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}}/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}}/scope-mappings">Scope</a></li>
<li class="active"><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}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">
<h2>OAuth Client Installation</h2> <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><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 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}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
</ul> </ul>
<div id="content"> <div id="content">

View file

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

View file

@ -51,4 +51,14 @@ public interface ClientModel {
public void setSecret(String secret); public void setSecret(String secret);
RealmModel getRealm(); 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 $ * @version $Revision: 1 $
*/ */
public interface OAuthClientModel extends ClientModel { 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()); return secret.equals(entity.getSecret());
} }
@Override
public int getNotBefore() {
return entity.getNotBefore();
}
@Override
public void setNotBefore(int notBefore) {
entity.setNotBefore(notBefore);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View file

@ -18,5 +18,8 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
super(realm, entity); 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 boolean enabled;
private String secret; private String secret;
private long allowedClaimsMask; private long allowedClaimsMask;
private int notBefore;
@ElementCollection @ElementCollection
@ -92,4 +93,12 @@ public class ClientEntity {
public void setSecret(String secret) { public void setSecret(String secret) {
this.secret = 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); application.setAllowedClaimsMask(mask);
} }
@Override
public int getNotBefore() {
return application.getNotBefore();
}
@Override
public void setNotBefore(int notBefore) {
application.setNotBefore(notBefore);
}
@Override @Override
public RoleAdapter getRole(String name) { public RoleAdapter getRole(String name) {

View file

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

View file

@ -23,6 +23,7 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
private String managementUrl; private String managementUrl;
private String baseUrl; private String baseUrl;
private String secret; private String secret;
private int notBefore;
private String realmId; private String realmId;
private long allowedClaimsMask; private long allowedClaimsMask;
@ -146,6 +147,15 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
this.defaultRoles = defaultRoles; this.defaultRoles = defaultRoles;
} }
@MongoField
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
@Override @Override
public void afterRemove(MongoStoreInvocationContext context) { public void afterRemove(MongoStoreInvocationContext context) {
// Remove all roles, which belongs to this application // 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 realmId;
private String secret; private String secret;
private long allowedClaimsMask; private long allowedClaimsMask;
private int notBefore;
private List<String> scopeIds; private List<String> scopeIds;
private List<String> webOrigins; private List<String> webOrigins;
private List<String> redirectUris; private List<String> redirectUris;
@ -96,8 +97,14 @@ public class OAuthClientEntity extends AbstractMongoIdentifiableEntity implement
this.scopeIds = scopeIds; this.scopeIds = scopeIds;
} }
@MongoField
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
@Override @Override
public void afterRemove(MongoStoreInvocationContext context) { public void afterRemove(MongoStoreInvocationContext context) {

View file

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

View file

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

View file

@ -106,7 +106,6 @@ public class RealmManager {
public void updateRealm(RealmRepresentation rep, RealmModel realm) { public void updateRealm(RealmRepresentation rep, RealmModel realm) {
if (rep.getRealm() != null) { if (rep.getRealm() != null) {
logger.info("Updating realm name to " + rep.getRealm());
realm.setName(rep.getRealm()); realm.setName(rep.getRealm());
} }
if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled()); if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
@ -128,10 +127,10 @@ public class RealmManager {
if (rep.getRequiredCredentials() != null) { if (rep.getRequiredCredentials() != null) {
realm.updateRequiredCredentials(rep.getRequiredCredentials()); realm.updateRequiredCredentials(rep.getRequiredCredentials());
} }
realm.setLoginTheme(rep.getLoginTheme()); if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
realm.setAccountTheme(rep.getAccountTheme()); 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) { if (rep.getDefaultRoles() != null) {
realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()])); realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
@ -232,8 +231,8 @@ public class RealmManager {
newRealm.setPrivateKeyPem(rep.getPrivateKey()); newRealm.setPrivateKeyPem(rep.getPrivateKey());
newRealm.setPublicKeyPem(rep.getPublicKey()); newRealm.setPublicKeyPem(rep.getPublicKey());
} }
newRealm.setLoginTheme(rep.getLoginTheme()); if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
newRealm.setAccountTheme(rep.getAccountTheme()); if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
Map<String, UserModel> userMap = new HashMap<String, UserModel>(); Map<String, UserModel> userMap = new HashMap<String, UserModel>();
@ -245,7 +244,7 @@ public class RealmManager {
addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD); addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
} }
newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy())); if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
if (rep.getUsers() != null) { if (rep.getUsers() != null) {
for (UserRepresentation userRep : rep.getUsers()) { 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() ResteasyClient client = new ResteasyClientBuilder()
.disableTrustManager() // todo fix this, should have a trust manager or a good default .disableTrustManager() // todo fix this, should have a trust manager or a good default
.build(); .build();
try { try {
for (ApplicationModel application : realm.getApplications()) { for (ApplicationModel application : realm.getApplications()) {
pushRevocationPolicies(realm, application, client); pushRevocationPolicy(realm, application, realm.getNotBefore(), client);
} }
} finally { } finally {
client.close(); 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; if (realm.getNotBefore() <= 0) return false;
String managementUrl = resource.getManagementUrl(); String managementUrl = resource.getManagementUrl();
if (managementUrl != null) { 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); String token = new TokenManager().encodeToken(realm, adminAction);
logger.info("pushRevocation resource: {0} url: {1}", resource.getName(), managementUrl); 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)); 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; 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>()); 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) { public AccessToken createClientAccessToken(String scopeParam, RealmModel realm, ClientModel client, UserModel user, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested) {
AccessScope scopeMap = null; AccessScope scopeMap = null;
if (scopeParam != null) scopeMap = decodeScope(scopeParam); 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.ApplicationManager;
import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.util.JsonSerialization; 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.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;
@ -112,7 +109,7 @@ public class RealmAdminResource {
@POST @POST
public void pushRevocation() { public void pushRevocation() {
auth.requireManage(); auth.requireManage();
new ResourceAdminManager().pushRevocationPolicies(realm); new ResourceAdminManager().pushRealmRevocationPolicy(realm);
} }
} }