diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
index 3f39818c19..820048677e 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
@@ -491,6 +491,72 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'ApplicationProtocolMapperCreateCtrl'
})
+
+ .when('/realms/:realm/oauth-clients/:oauth/mappers', {
+ templateUrl : resourceUrl + '/partials/oauth-client-mappers.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ oauth : function(OAuthClientLoader) {
+ return OAuthClientLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ }
+ },
+ controller : 'OAuthClientProtocolMapperListCtrl'
+ })
+ .when('/realms/:realm/oauth-clients/:oauth/add-mappers', {
+ templateUrl : resourceUrl + '/partials/oauth-client-mappers-add.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ oauth : function(OAuthClientLoader) {
+ return OAuthClientLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ }
+ },
+ controller : 'OAuthClientAddBuiltinProtocolMapperCtrl'
+ })
+ .when('/realms/:realm/oauth-clients/:oauth/mappers/:id', {
+ templateUrl : resourceUrl + '/partials/oauth-client-protocol-mapper-detail.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ oauth : function(OAuthClientLoader) {
+ return OAuthClientLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ },
+ mapper : function(OAuthClientProtocolMapperLoader) {
+ return OAuthClientProtocolMapperLoader();
+ }
+
+ },
+ controller : 'OAuthClientProtocolMapperCtrl'
+ })
+ .when('/create/oauth-client/:realm/:oauth/mappers', {
+ templateUrl : resourceUrl + '/partials/oauth-client-protocol-mapper-detail.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ },
+ oauth : function(OAuthClientLoader) {
+ return OAuthClientLoader();
+ }
+ },
+ controller : 'OAuthClientProtocolMapperCreateCtrl'
+ })
+
.when('/realms/:realm/applications/:application/sessions', {
templateUrl : resourceUrl + '/partials/application-sessions.html',
resolve : {
@@ -1411,7 +1477,7 @@ module.directive('kcNavigationApplication', function () {
scope: true,
restrict: 'E',
replace: true,
- templateUrl: resourceUrl + '/templates/kc-navigation-application.html',
+ templateUrl: resourceUrl + '/templates/kc-navigation-application.html'
}
});
@@ -1420,7 +1486,7 @@ module.directive('kcNavigationOauthClient', function () {
scope: true,
restrict: 'E',
replace: true,
- templateUrl: resourceUrl + '/templates/kc-navigation-oauth-client.html',
+ templateUrl: resourceUrl + '/templates/kc-navigation-oauth-client.html'
}
});
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
index 1237f57301..a55b9e3754 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
@@ -415,3 +415,197 @@ module.controller('OAuthClientIdentityProviderCtrl', function($scope, $route, re
}, true);
});
+module.controller('OAuthClientProtocolMapperListCtrl', function($scope, realm, oauth, serverInfo,
+ OAuthClientProtocolMappersByProtocol,
+ $http, $location, Dialog, Notifications) {
+ $scope.realm = realm;
+ $scope.oauth = oauth;
+ if (oauth.protocol == null) {
+ oauth.protocol = 'openid-connect';
+ }
+
+ var protocolMappers = serverInfo.protocolMapperTypes[oauth.protocol];
+ var mapperTypes = {};
+ for (var i = 0; i < protocolMappers.length; i++) {
+ mapperTypes[protocolMappers[i].id] = protocolMappers[i];
+ }
+ $scope.mapperTypes = mapperTypes;
+
+
+ var updateMappers = function() {
+ $scope.mappers = OAuthClientProtocolMappersByProtocol.query({realm : realm.realm, oauth : oauth.id, protocol : oauth.protocol});
+ };
+
+ updateMappers();
+});
+
+module.controller('OAuthClientAddBuiltinProtocolMapperCtrl', function($scope, realm, oauth, serverInfo,
+ OAuthClientProtocolMappersByProtocol,
+ $http, $location, Dialog, Notifications) {
+ $scope.realm = realm;
+ $scope.oauth = oauth;
+ if (oauth.protocol == null) {
+ oauth.protocol = 'openid-connect';
+ }
+
+ var protocolMappers = serverInfo.protocolMapperTypes[oauth.protocol];
+ var mapperTypes = {};
+ for (var i = 0; i < protocolMappers.length; i++) {
+ mapperTypes[protocolMappers[i].id] = protocolMappers[i];
+ }
+ $scope.mapperTypes = mapperTypes;
+
+
+
+
+ var updateMappers = function() {
+ var appMappers = OAuthClientProtocolMappersByProtocol.query({realm : realm.realm, oauth : oauth.id, protocol : oauth.protocol}, function() {
+ var builtinMappers = serverInfo.builtinProtocolMappers[oauth.protocol];
+ for (var i = 0; i < appMappers.length; i++) {
+ for (var j = 0; j < builtinMappers.length; j++) {
+ if (builtinMappers[j].name == appMappers[i].name
+ && builtinMappers[j].protocolMapper == appMappers[i].protocolMapper) {
+ console.log('removing: ' + builtinMappers[j].name);
+ builtinMappers.splice(j, 1);
+ break;
+ }
+ }
+ }
+ for (var j = 0; j < builtinMappers.length; j++) {
+ console.log('builtin left: ' + builtinMappers[j].name);
+ }
+ $scope.mappers = builtinMappers;
+ for (var i = 0; i < $scope.mappers.length; i++) {
+ $scope.mappers[i].isChecked = false;
+ }
+
+
+ });
+ };
+
+ updateMappers();
+
+ $scope.add = function() {
+ var toAdd = [];
+ for (var i = 0; i < $scope.mappers.length; i++) {
+ if ($scope.mappers[i].isChecked) {
+ delete $scope.mappers[i].isChecked;
+ toAdd.push($scope.mappers[i]);
+ }
+ }
+ $http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients-by-id/' + oauth.id + '/protocol-mappers/add-models',
+ toAdd).success(function() {
+ Notifications.success("Mappers added");
+ $location.url('/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/mappers');
+ }).error(function() {
+ Notifications.error("Error adding mappers");
+ $location.url('/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/mappers');
+ });
+ };
+
+});
+
+module.controller('OAuthClientProtocolMapperCtrl', function($scope, realm, serverInfo, oauth, mapper, OAuthClientProtocolMapper, Notifications, Dialog, $location) {
+ if (oauth.protocol == null) {
+ oauth.protocol = 'openid-connect';
+ }
+ $scope.realm = realm;
+ $scope.oauth = oauth;
+ $scope.create = false;
+ var protocol = oauth.protocol;
+ $scope.protocol = oauth.protocol;
+ $scope.mapper = angular.copy(mapper);
+ var oldCopy = angular.copy($scope.realm);
+ $scope.changed = false;
+
+ var protocolMappers = serverInfo.protocolMapperTypes[protocol];
+ for (var i = 0; i < protocolMappers.length; i++) {
+ if (protocolMappers[i].id == mapper.protocolMapper) {
+ $scope.mapperType = protocolMappers[i];
+ }
+ }
+ $scope.$watch(function() {
+ return $location.path();
+ }, function() {
+ $scope.path = $location.path().substring(1).split("/");
+ });
+
+ $scope.$watch('mapper', function() {
+ if (!angular.equals($scope.mapper, mapper)) {
+ $scope.changed = true;
+ }
+ }, true);
+
+ $scope.save = function() {
+ OAuthClientProtocolMapper.update({
+ realm : realm.realm,
+ oauth: oauth.id,
+ id : mapper.id
+ }, $scope.mapper, function() {
+ $scope.changed = false;
+ mapper = angular.copy($scope.mapper);
+ $location.url("/realms/" + realm.realm + '/oauth-clients/' + oauth.id + "/mappers/" + mapper.id);
+ Notifications.success("Your changes have been saved.");
+ });
+ };
+
+ $scope.reset = function() {
+ $scope.mapper = angular.copy(mapper);
+ $scope.changed = false;
+ };
+
+ $scope.cancel = function() {
+ //$location.url("/realms");
+ window.history.back();
+ };
+
+ $scope.remove = function() {
+ Dialog.confirmDelete($scope.mapper.name, 'mapper', function() {
+ OAuthClientProtocolMapper.remove({ realm: realm.realm, oauth: oauth.id, id : $scope.mapper.id }, function() {
+ Notifications.success("The mapper has been deleted.");
+ $location.url("/realms/" + realm.realm + '/oauth-clients/' + oauth.id + "/mappers");
+ });
+ });
+ };
+
+});
+
+module.controller('OAuthClientProtocolMapperCreateCtrl', function($scope, realm, serverInfo, oauth, OAuthClientProtocolMapper, Notifications, Dialog, $location) {
+ if (oauth.protocol == null) {
+ oauth.protocol = 'openid-connect';
+ }
+ $scope.realm = realm;
+ $scope.oauth = oauth;
+ $scope.create = true;
+ var protocol = oauth.protocol;
+ $scope.protocol = protocol;
+ $scope.mapper = { protocol : oauth.protocol, config: {}};
+ $scope.mapperTypes = serverInfo.protocolMapperTypes[protocol];
+
+ $scope.$watch(function() {
+ return $location.path();
+ }, function() {
+ $scope.path = $location.path().substring(1).split("/");
+ });
+
+ $scope.save = function() {
+ $scope.mapper.protocolMapper = $scope.mapperType.id;
+ OAuthClientProtocolMapper.save({
+ realm : realm.realm, oauth: oauth.id
+ }, $scope.mapper, function(data, headers) {
+ var l = headers().location;
+ var id = l.substring(l.lastIndexOf("/") + 1);
+ $location.url("/realms/" + realm.realm + '/oauth-clients/' + oauth.id + "/mappers/" + id);
+ Notifications.success("Mapper has been created.");
+ });
+ };
+
+ $scope.cancel = function() {
+ //$location.url("/realms");
+ window.history.back();
+ };
+
+
+});
+
+
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
index decbbff93e..e5db07fa07 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
@@ -89,6 +89,16 @@ module.factory('ApplicationProtocolMapperLoader', function(Loader, ApplicationPr
});
});
+module.factory('OAuthClientProtocolMapperLoader', function(Loader, OAuthClientProtocolMapper, $route, $q) {
+ return Loader.get(OAuthClientProtocolMapper, function() {
+ return {
+ realm : $route.current.params.realm,
+ oauth : $route.current.params.oauth,
+ id: $route.current.params.id
+ }
+ });
+});
+
module.factory('UserLoader', function(Loader, User, $route, $q) {
return Loader.get(User, function() {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
index b6e306b896..b3b0edfcee 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
@@ -188,6 +188,8 @@ module.factory('ServerInfo', function($resource) {
return $resource(authUrl + '/admin/serverinfo');
});
+
+
module.factory('ApplicationProtocolMapper', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/protocol-mappers/models/:id', {
realm : '@realm',
@@ -200,6 +202,28 @@ module.factory('ApplicationProtocolMapper', function($resource) {
});
});
+module.factory('OAuthClientProtocolMapper', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/oauth-clients-by-id/:oauth/protocol-mappers/models/:id', {
+ realm : '@realm',
+ oauth: '@oauth',
+ id : "@id"
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('OAuthClientProtocolMappersByProtocol', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/oauth-clients-by-id/:oauth/protocol-mappers/protocol/:protocol', {
+ realm : '@realm',
+ oauth : "@oauth",
+ protocol : "@protocol"
+ });
+});
+
+
+
module.factory('User', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/users/:userId', {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-mappers-add.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-mappers-add.html
index 95c4eead09..07ec62c626 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-mappers-add.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-mappers-add.html
@@ -35,7 +35,7 @@
- {{mapper.name}}
+ {{mapper.name}}
{{mapperTypes[mapper.protocolMapper].category}}
{{mapperTypes[mapper.protocolMapper].name}}
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers-add.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers-add.html
new file mode 100755
index 0000000000..0b0284e060
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers-add.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+ OAuth Clients
+ {{oauth.name}}
+ {{oauth.name}} Mappers
+ Add Builtin Protocol Mappers
+
+
Add Builtin Protocol Mappers
+
+
+
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers.html
new file mode 100755
index 0000000000..83a722e7e9
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-mappers.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ OAuth Clients
+ {{oauth.name}}
+ Protocol Mappers
+
+
{{realm.realm}} {{oauth.name}} {{oauth.protocol}} Protocol Mappers
+
+
+
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-protocol-mapper-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-protocol-mapper-detail.html
new file mode 100755
index 0000000000..a98bbe7cf6
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-protocol-mapper-detail.html
@@ -0,0 +1,103 @@
+
+
+
+
+
+ OAuth Clients
+ {{oauth.name}}
+ {{oauth.name}} Mappers
+ Create Protocol Mapper
+
+
+
+ OAuth Clients
+ {{oauth.name}}
+ {{oauth.name}} Mappers
+ {{mapper.name}}
+
+
{{mapper.name}} Protocol Mapper
+
Create Protocol Mapper
+
* Required fields
+
+
+
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-oauth-client.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-oauth-client.html
index db40ee5582..8c35518959 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-oauth-client.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-oauth-client.html
@@ -1,7 +1,7 @@
Settings
Credentials
- Claims
+ Mappers
Scope
Revocation
Identity Provider
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index a51f8013d7..897ac6f836 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -635,7 +635,18 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
appData.setEnabled(true);
getMongoStore().insertEntity(appData, invocationContext);
- ApplicationModel model = new ApplicationAdapter(session, this, appData, invocationContext);
+ final ApplicationModel model = new ApplicationAdapter(session, this, appData, invocationContext);
+ session.getKeycloakSessionFactory().publish(new ApplicationCreationEvent() {
+ @Override
+ public ApplicationModel getCreatedApplication() {
+ return model;
+ }
+
+ @Override
+ public ClientModel getCreatedClient() {
+ return model;
+ }
+ });
return model;
}
@@ -657,7 +668,18 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
oauthClient.setName(name);
getMongoStore().insertEntity(oauthClient, invocationContext);
- OAuthClientAdapter model = new OAuthClientAdapter(session, this, oauthClient, invocationContext);
+ final OAuthClientAdapter model = new OAuthClientAdapter(session, this, oauthClient, invocationContext);
+ session.getKeycloakSessionFactory().publish(new OAuthClientCreationEvent() {
+ @Override
+ public OAuthClientModel getCreatedOAuthClient() {
+ return model;
+ }
+
+ @Override
+ public ClientModel getCreatedClient() {
+ return model;
+ }
+ });
return model;
}