keycloak-uncached
Changes
examples/as7-eap-demo/server/pom.xml 21(+0 -21)
examples/as7-eap-dev/server/pom.xml 21(+0 -21)
forms/pom.xml 5(+0 -5)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java 1(+0 -1)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java 1(+0 -1)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java 1(+0 -1)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java 879(+0 -879)
model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationScopeMappingEntity.java 29(+29 -0)
model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationUserRoleMappingEntity.java 29(+29 -0)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java 25(+20 -5)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoDBSessionFactory.java 6(+3 -3)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java 10(+0 -10)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/PasswordCredentialHandler.java 8(+4 -4)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/TOTPCredentialHandler.java 11(+4 -7)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/PasswordData.java 4(+2 -2)
model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkKeycloakSession.java 2(+0 -2)
model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkModelProvider.java 77(+77 -0)
model/picketlink/src/main/java/org/keycloak/models/picketlink/relationships/RealmListingRelationship.java 2(+0 -2)
model/pom.xml 2(+1 -1)
pom.xml 4(+2 -2)
services/pom.xml 6(+6 -0)
testsuite/integration/pom.xml 2(+2 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java 15(+7 -8)
testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java 6(+2 -4)
testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java 3(+1 -2)
testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java 5(+2 -3)
testsuite/performance/pom.xml 2(+2 -0)
testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java 8(+4 -4)
testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java 4(+2 -2)
testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java 4(+2 -2)
testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java 4(+2 -2)
Details
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/index.html b/admin-ui/src/main/resources/META-INF/resources/admin/index.html
index 9487218..4be31ec 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/index.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/index.html
@@ -73,8 +73,10 @@
</button>
</div>
- <div id="loading">
- <i class="icon-spinner icon-spin"></i> Loading...
+ <div id="loading" class="loading-backdrop">
+ <div class="loading">
+ <span>Loading...</span>
+ </div>
</div>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
index 7025d2e..07579f7 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
@@ -11,6 +11,9 @@ module.config([ '$routeProvider', function($routeProvider) {
resolve : {
realm : function(RealmLoader) {
return {};
+ },
+ roles : function() {
+ return {};
}
},
controller : 'RealmDetailCtrl'
@@ -20,6 +23,9 @@ module.config([ '$routeProvider', function($routeProvider) {
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
+ },
+ roles : function(RoleListLoader) {
+ return RoleListLoader();
}
},
controller : 'RealmDetailCtrl'
@@ -240,6 +246,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
application : function() {
return {};
+ },
+ roles : function() {
+ return {};
}
},
controller : 'ApplicationDetailCtrl'
@@ -255,6 +264,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
application : function(ApplicationLoader) {
return ApplicationLoader();
+ },
+ roles : function(ApplicationRoleListLoader) {
+ return ApplicationRoleListLoader();
}
},
controller : 'ApplicationDetailCtrl'
@@ -368,10 +380,42 @@ module.directive('collapsed', function() {
}
});
-
-
-
-
+/**
+ * Directive for presenting an ON-OFF switch for checkbox.
+ * Usage: <input ng-model="mmm" name="nnn" id="iii" onoffswitch [on-text="ooo" off-text="fff"] />
+ */
+module.directive('onoffswitch', function() {
+ return {
+ restrict: "EA",
+ require: 'ngModel',
+ replace: true,
+ scope: {
+ ngModel: '=',
+ ngBind: '=',
+ name: '=',
+ id: '=',
+ onText: '@onText',
+ offText: '@offText'
+ },
+ compile: function(element, attrs) {
+ if (!attrs.onText) { attrs.onText = "ON"; }
+ if (!attrs.offText) { attrs.offText = "OFF"; }
+
+ var html = "<div class=\"onoffswitch\">" +
+ "<input type=\"checkbox\" data-ng-model=\"ngModel\" class=\"onoffswitch-checkbox\" name=\"" + attrs.name + "\" id=\"" + attrs.id + "\">" +
+ "<label for=\"" + attrs.id + "\" class=\"onoffswitch-label\">" +
+ "<span class=\"onoffswitch-inner\">" +
+ "<span class=\"onoffswitch-active\">{{onText}}</span>" +
+ "<span class=\"onoffswitch-inactive\">{{offText}}</span>" +
+ "</span>" +
+ "<span class=\"onoffswitch-switch\"></span>" +
+ "</label>" +
+ "</div>";
+
+ element.replaceWith($(html));
+ }
+ }
+});
module.directive('kcInput', function() {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers.js
index a154da3..d5908aa 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers.js
@@ -21,3 +21,16 @@ function randomString(len) {
return randomString;
}
+function getAvailableRoles(roles, systemRoles){
+ var complement = [];
+
+ for (var i = 0; i < roles.length; i++){
+ var roleName = roles[i].name;
+
+ if (systemRoles.indexOf(roleName) < 0){
+ complement.push(roleName);
+ }
+ }
+
+ return complement;
+}
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
index cc28637..7b74454 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
@@ -171,7 +171,7 @@ module.controller('ApplicationListCtrl', function($scope, realm, applications, A
});
});
-module.controller('ApplicationDetailCtrl', function($scope, realm, application, Application, $location, Dialog, Notifications) {
+module.controller('ApplicationDetailCtrl', function($scope, realm, application, roles, Application, $location, Dialog, Notifications) {
console.log('ApplicationDetailCtrl');
$scope.realm = realm;
@@ -182,6 +182,17 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
$scope.application = {};
}
+ console.log(application);
+
+ var systemRoles = ["*", "KEYCLOAK_APPLICATION","KEYCLOAK_IDENTITY_REQUESTER"];
+ var availableRoles = getAvailableRoles(roles, systemRoles);
+
+ $scope.appDefaultRolesOptions = {
+ 'multiple' : true,
+ 'simple_tags' : true,
+ 'tags' : availableRoles
+ };
+
$scope.$watch(function() {
return $location.path();
}, function() {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
index fa11a54..3f0e6c3 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
@@ -44,11 +44,20 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
}
});
-module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
+module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, roles, $http, $location, Dialog, Notifications) {
$scope.createRealm = !realm.id;
console.log('RealmDetailCtrl');
+ var systemRoles = ["*", "KEYCLOAK_APPLICATION","KEYCLOAK_IDENTITY_REQUESTER"];
+ var availableRoles = getAvailableRoles(roles, systemRoles);
+
+ $scope.realmDefaultRolesOptions = {
+ 'multiple' : true,
+ 'simple_tags' : true,
+ 'tags' : availableRoles
+ };
+
if ($scope.createRealm) {
$scope.realm = {
enabled: true,
@@ -73,6 +82,8 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
$scope.realm.requireSsl = !realm.sslNotRequired;
}
+ $scope.social = $scope.realm.social;
+
var oldCopy = angular.copy($scope.realm);
@@ -104,6 +115,7 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
}
$location.url("/realms/" + id);
Notifications.success("The realm has been created.");
+ $scope.social = $scope.realm.social;
});
});
} else {
@@ -122,6 +134,7 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
});
$location.url("/realms/" + id);
Notifications.success("Your changes have been saved to the realm.");
+ $scope.social = $scope.realm.social;
});
}
} else {
@@ -207,8 +220,13 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
$scope.realm["socialProviders"] = realm.socialProviders;
}
- // Hardcoded provider list
- $scope.availableProviders = [ "google", "facebook", "twitter"];
+ // Hardcoded provider list in form of map providerId:providerName
+ $scope.allProviders = { google:"Google", facebook:"Facebook", twitter:"Twitter" };
+ $scope.availableProviders = [];
+
+ for (var provider in $scope.allProviders){
+ $scope.availableProviders.push(provider);
+ }
var oldCopy = angular.copy($scope.realm);
$scope.changed = false;
@@ -226,6 +244,9 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
// Fill in configured providers
var initSocial = function() {
+ // postSaveProviders is used for remembering providers which were already validated after pressing the save button
+ // thanks to this it's easy to distinguish between newly added fields and those already tried to be saved
+ $scope.postSaveProviders = [];
$scope.unsetProviders = [];
$scope.configuredProviders = [];
@@ -241,7 +262,7 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
// If no providers are already configured, you can add any of them
if ($scope.configuredProviders.length == 0){
- $scope.unsetProviders = $scope.availableProviders;
+ $scope.unsetProviders = $scope.availableProviders.slice(0);
} else {
for (var i = 0; i < $scope.availableProviders.length; i++){
var providerId = $scope.availableProviders[i];
@@ -270,6 +291,13 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
delete $scope.realm.socialProviders[pId+".key"];
delete $scope.realm.socialProviders[pId+".secret"];
$scope.configuredProviders.remove($scope.configuredProviders.indexOf(pId));
+
+ // Removing from postSaveProviders, so the empty fields are not red if the provider is added to the list again
+ var rId = $scope.postSaveProviders.indexOf(pId);
+ if (rId > -1){
+ $scope.postSaveProviders.remove(rId)
+ }
+
$scope.unsetProviders.push(pId);
};
@@ -280,8 +308,6 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
}, true);
$scope.save = function() {
- $scope.saveClicked = true;
-
if ($scope.realmForm.$valid) {
var realmCopy = angular.copy($scope.realm);
realmCopy.social = true;
@@ -289,10 +315,12 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
Realm.update(realmCopy, function () {
$location.url("/realms/" + realm.id + "/social-settings");
Notifications.success("Saved changes to realm");
+ oldCopy = realmCopy;
});
} else {
$scope.realmForm.showErrors = true;
Notifications.error("Some required fields are missing values.");
+ $scope.postSaveProviders = $scope.configuredProviders.slice(0);
}
};
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
index 2c11b73..06e8b54 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
@@ -44,17 +44,7 @@
<div class="form-group clearfix block">
<label for="enabled" class="control-label">Enabled</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="application.enabled" class="onoffswitch-checkbox"
- name="enabled" id="enabled">
- <label for="enabled" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="application.enabled" name="enabled" id="enabled" onoffswitch />
</div>
<div class="form-group">
<label for="baseUrl" class="control-label">Base URL</label>
@@ -103,6 +93,16 @@
</div>
</div>
</fieldset>
+ <fieldset>
+ <legend uncollapsed><span class="text">Default Roles</span></legend>
+ <div class="form-group">
+ <label for="default-roles" class="control-label two-lines">Default Application Roles</label>
+
+ <div class="controls">
+ <input id="default-roles" type="text" ui-select2="appDefaultRolesOptions" ng-model="application.defaultRoles" placeholder="Type a role and enter">
+ </div>
+ </div>
+ </fieldset>
<div class="form-actions" data-ng-show="create">
<button type="submit" data-ng-click="save()" data-ng-show="changed" class="primary">Save
</button>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
index d35d8cd..b530a0c 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
@@ -5,7 +5,7 @@
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li class="active"><a href="#/realms/{{realm.id}}">General</a></li>
- <li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
+ <li data-ng-show="social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
@@ -34,112 +34,47 @@
</div>
<div class="form-group">
<label for="enabled" class="control-label">Enabled</label>
-
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.enabled" class="onoffswitch-checkbox"
- name="enabled" id="enabled">
- <label for="enabled" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
</div>
</fieldset>
<fieldset>
<legend uncollapsed><span class="text">Login Options</span></legend>
<div class="form-group clearfix block">
<label for="social" class="control-label">Social login</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.social" class="onoffswitch-checkbox" name="social" id="social">
- <label for="social" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.social" name="social" id="social" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="registrationAllowed" class="control-label">User registration</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.registrationAllowed" class="onoffswitch-checkbox" name="registrationAllowed" id="registrationAllowed">
- <label for="registrationAllowed" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="resetPasswordAllowed" class="control-label">Reset password</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.resetPasswordAllowed" class="onoffswitch-checkbox" name="resetPasswordAllowed" id="resetPasswordAllowed">
- <label for="resetPasswordAllowed" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="verifyEmail" class="control-label">Verify email</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.verifyEmail" class="onoffswitch-checkbox" name="verifyEmail" id="verifyEmail">
- <label for="verifyEmail" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="accountManagement" class="control-label two-lines">User account management</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.accountManagement" class="onoffswitch-checkbox"
- name="accountManagement" id="accountManagement">
- <label for="accountManagement" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.accountManagement" name="accountManagement" id="accountManagement" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="requireSsl" class="control-label">Require SSL</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.requireSsl" class="onoffswitch-checkbox" name="requireSsl" id="requireSsl">
- <label for="requireSsl" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
</div>
<div class="form-group">
<label for="cookieLoginAllowed" class="control-label">Cookie login allowed</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.cookieLoginAllowed" class="onoffswitch-checkbox" name="cookieLoginAllowed" id="cookieLoginAllowed">
- <label for="cookieLoginAllowed" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
+ <input ng-model="realm.cookieLoginAllowed" name="cookieLoginAllowed" id="cookieLoginAllowed" onoffswitch />
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend uncollapsed><span class="text">Default Roles</span></legend>
+ <div class="form-group">
+ <label for="default-roles" class="control-label two-lines">Default Realm Roles</label>
+
+ <div class="controls">
+ <input id="default-roles" type="text" ui-select2="realmDefaultRolesOptions" ng-model="realm.defaultRoles" placeholder="Type a role and enter">
</div>
</div>
</fieldset>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
index 16f7b78..87e0ed1 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
@@ -1,5 +1,5 @@
<ul data-ng-hide="createRealm">
- <li data-ng-class="(!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' || path[2] == 'social-settings' || path[2] == 'required-credentials') && 'active'"><a href="#/realms/{{realm.id}}">Settings</a></li>
+ <li data-ng-class="(!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' || path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'smtp-settings') && 'active'"><a href="#/realms/{{realm.id}}">Settings</a></li>
<li data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.id}}/users">Users</a>
</li>
<li data-ng-class="(path[2] == 'applications' || path[1] == 'application') && 'active'"><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
index 6abd4ee..dd24ea7 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
@@ -42,45 +42,18 @@
</div>
<div class="form-group clearfix">
<label for="smtpSSL" class="control-label">Enable SSL</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.smtpServer.ssl" class="onoffswitch-checkbox" name="smtpSSL" id="smtpSSL">
- <label for="smtpSSL" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.smtpServer.ssl" name="smtpSSL" id="smtpSSL" onoffswitch />
</div>
<div class="form-group clearfix">
<label for="smtpStartTLS" class="control-label">Enable StartTLS</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.smtpServer.starttls" class="onoffswitch-checkbox" name="smtpStartTLS" id="smtpStartTLS">
- <label for="smtpStartTLS" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.smtpServer.starttls" name="smtpStartTLS" id="smtpStartTLS" onoffswitch />
</div>
</fieldset>
<fieldset>
<legend collapsed><span class="text">Authentication</span></legend>
<div class="form-group clearfix">
<label for="smtpAuth" class="control-label">Enabled</label>
- <div class="onoffswitch">
- <input type="checkbox" data-ng-model="realm.smtpServer.auth" class="onoffswitch-checkbox" name="smtpAuth" id="smtpAuth">
- <label for="smtpAuth" class="onoffswitch-label">
- <span class="onoffswitch-inner">
- <span class="onoffswitch-active">ON</span>
- <span class="onoffswitch-inactive">OFF</span>
- </span>
- <span class="onoffswitch-switch"></span>
- </label>
- </div>
+ <input ng-model="realm.smtpServer.auth" name="smtpAuth" id="smtpAuth" onoffswitch />
</div>
<div class="form-group clearfix">
<label for="smtpUsername" class="control-label">Username <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
index a046cc5..b0ef465 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
@@ -30,7 +30,8 @@
<div class="actions">
<div class="select-rcue">
<select ng-model="newProviderId"
- ng-options="p for p in unsetProviders"></select>
+ ng-options="p as allProviders[p] for p in unsetProviders"
+ placeholder="Please select"></select>
</div>
<div>
<button ng-click="addProvider()" ng-disabled="">Add Provider</button>
@@ -49,16 +50,16 @@
<tr ng-repeat="pId in configuredProviders">
<td>
<div class="clearfix">
- <input class="input-small disabled" type="text" placeholder="Key" value="{{pId}}" readonly>
+ <input class="input-small disabled" type="text" value="{{allProviders[pId]}}" readonly>
</div>
</td>
<td>
<input class="input-small" type="text" placeholder="Key" ng-model="realm.socialProviders[pId+'.key']"
- ng-class="{'dirty': saveClicked}" required>
+ ng-class="{'dirty': postSaveProviders.indexOf(pId) > -1}" required>
</td>
<td>
<input class="input-small" type="text" placeholder="Secret" ng-model="realm.socialProviders[pId+'.secret']"
- ng-class="{'dirty': saveClicked}" required>
+ ng-class="{'dirty': postSaveProviders.indexOf(pId) > -1}" required>
</td>
<td>
<div class="action-div"><i class="icon-question" ng-click="openHelp(pId)"></i></div>
diff --git a/admin-ui/src/main/resources/META-INF/web-fragment.xml b/admin-ui/src/main/resources/META-INF/web-fragment.xml
index af5af31..cf5933b 100755
--- a/admin-ui/src/main/resources/META-INF/web-fragment.xml
+++ b/admin-ui/src/main/resources/META-INF/web-fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd ">
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd ">
</web-fragment>
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
index 6b3ca67..1cea3b5 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
@@ -55,9 +55,19 @@ body {
color: #fff;
font-weight: bold;
}
+.loading-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1031;
+ background-color: #FFFFFF;
+ opacity: 0.75;
+}
.loading {
position: fixed;
- z-index: 1000;
+ z-index: 1032;
top: 50%;
left: 50%;
width: 6em;
@@ -75,10 +85,14 @@ body {
border-radius: 0.4em;
}
.loading span {
- font-size: 1.1em;
+ background: url(img/loader.gif) no-repeat center top;
+ font-size: 1.2em;
color: #666;
display: inline-block;
padding-top: 0.36363636363636em;
+ margin-top: -2.27272727272727em;
+ margin-left: -2.27272727272727em;
+ padding-top: 2.90909090909091em;
}
/* Header */
.header.rcue {
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
index 0109fe5..d5bfdf2 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
@@ -74,9 +74,20 @@ body {
}
}
+.loading-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1031;
+ background-color: #FFFFFF;
+ opacity: 0.75;
+}
+
.loading {
position: fixed;
- z-index: 1000;
+ z-index: 1032;
top: 50%;
left: 50%;
width: 6em;
@@ -93,12 +104,16 @@ body {
padding: 0.3em;
border-radius: 0.4em;
}
-
+
span {
- font-size: 1.1em;
+ background: url(img/loader.gif) no-repeat center top;
+ font-size: 1.2em;
color: #666;
display: inline-block;
padding-top: 0.36363636363636em;
+ margin-top: -2.27272727272727em;
+ margin-left: -2.27272727272727em;
+ padding-top: 2.90909090909091em;
}
}
diff --git a/admin-ui-styles/src/main/resources/META-INF/web-fragment.xml b/admin-ui-styles/src/main/resources/META-INF/web-fragment.xml
index af5af31..cf5933b 100755
--- a/admin-ui-styles/src/main/resources/META-INF/web-fragment.xml
+++ b/admin-ui-styles/src/main/resources/META-INF/web-fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd ">
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd ">
</web-fragment>
diff --git a/core/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java b/core/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
index 0fde587..c4b4f7b 100755
--- a/core/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
+++ b/core/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
@@ -37,7 +37,8 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
.queryParam("state", state)
.build();
NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true);
- logger.info("NewCookie: " + cookie.toString());
+ logger.debug("NewCookie: " + cookie.toString());
+ logger.debug("Oauth Redirect to: " + url);
return Response.status(302)
.location(url)
.cookie(cookie).build();
diff --git a/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java b/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java
index 0a7f553..3b0a4e4 100755
--- a/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java
+++ b/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java
@@ -1,7 +1,6 @@
package org.keycloak.representations.idm.admin;
import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
/**
* Posted to managed client from admin server.
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 65281dc..c520fd3 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -28,7 +28,7 @@ public class RealmRepresentation {
protected String privateKey;
protected String publicKey;
protected List<RoleRepresentation> roles;
- protected String[] defaultRoles;
+ protected List<String> defaultRoles;
protected Set<String> requiredCredentials;
protected Set<String> requiredApplicationCredentials;
protected Set<String> requiredOAuthClientCredentials;
@@ -220,11 +220,11 @@ public class RealmRepresentation {
this.roles = roles;
}
- public String[] getDefaultRoles() {
+ public List<String> getDefaultRoles() {
return defaultRoles;
}
- public void setDefaultRoles(String[] defaultRoles) {
+ public void setDefaultRoles(List<String> defaultRoles) {
this.defaultRoles = defaultRoles;
}
diff --git a/core/src/main/java/org/keycloak/representations/SkeletonKeyToken.java b/core/src/main/java/org/keycloak/representations/SkeletonKeyToken.java
index 2b40251..601bbbe 100755
--- a/core/src/main/java/org/keycloak/representations/SkeletonKeyToken.java
+++ b/core/src/main/java/org/keycloak/representations/SkeletonKeyToken.java
@@ -4,7 +4,10 @@ import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.jboss.resteasy.jwt.JsonWebToken;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/core/src/test/java/org/keycloak/RSAVerifierTest.java b/core/src/test/java/org/keycloak/RSAVerifierTest.java
index 8841954..d169d37 100755
--- a/core/src/test/java/org/keycloak/RSAVerifierTest.java
+++ b/core/src/test/java/org/keycloak/RSAVerifierTest.java
@@ -6,13 +6,10 @@ import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.jboss.resteasy.jose.jws.JWSBuilder;
import org.jboss.resteasy.jwt.JsonSerialization;
-import org.keycloak.RSATokenVerifier;
-import org.keycloak.ResourceMetadata;
-import org.keycloak.VerificationException;
-import org.keycloak.representations.SkeletonKeyToken;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.keycloak.representations.SkeletonKeyToken;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
diff --git a/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java b/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
index cf5e459..c9d2e0d 100755
--- a/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
+++ b/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
@@ -5,9 +5,9 @@ import org.jboss.resteasy.jose.jws.JWSBuilder;
import org.jboss.resteasy.jose.jws.JWSInput;
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
import org.jboss.resteasy.jwt.JsonSerialization;
+import org.junit.Test;
import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken;
-import org.junit.Test;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
index 91657c9..54df669 100755
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
@@ -1,4 +1,4 @@
-<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<head>
diff --git a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
index fe8d990..bf1ca5a 100755
--- a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
+++ b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
@@ -1,4 +1,4 @@
-<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<head>
examples/as7-eap-demo/server/pom.xml 21(+0 -21)
diff --git a/examples/as7-eap-demo/server/pom.xml b/examples/as7-eap-demo/server/pom.xml
index 3282368..6d21685 100755
--- a/examples/as7-eap-demo/server/pom.xml
+++ b/examples/as7-eap-demo/server/pom.xml
@@ -37,11 +37,6 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-model-picketlink</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId>
<version>${project.version}</version>
</dependency>
@@ -76,22 +71,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-simple-schema</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-config</artifactId>
- </dependency>
- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
diff --git a/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java b/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
index b9bbc82..0b7b49d 100755
--- a/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
+++ b/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
@@ -1,11 +1,11 @@
package org.keycloak.example.demo;
import org.jboss.resteasy.jwt.JsonSerialization;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
import org.keycloak.services.resources.KeycloakApplication;
import javax.servlet.ServletContext;
diff --git a/examples/as7-eap-demo/server/src/main/resources/META-INF/persistence.xml b/examples/as7-eap-demo/server/src/main/resources/META-INF/persistence.xml
index cb5a1c3..b949715 100755
--- a/examples/as7-eap-demo/server/src/main/resources/META-INF/persistence.xml
+++ b/examples/as7-eap-demo/server/src/main/resources/META-INF/persistence.xml
@@ -2,27 +2,25 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
-
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
- <class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
- <class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
+
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.RoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
-
+
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/oauthGrantForm.jsp b/examples/as7-eap-demo/server/src/main/webapp/saas/oauthGrantForm.jsp
index 4bbd6df..d62b00e 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/saas/oauthGrantForm.jsp
+++ b/examples/as7-eap-demo/server/src/main/webapp/saas/oauthGrantForm.jsp
@@ -1,5 +1,6 @@
-<%@ page import="org.keycloak.models.*,org.keycloak.services.resources.*,javax.ws.rs.core.*,java.util.*" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="org.keycloak.models.RealmModel,org.keycloak.models.RoleModel,org.keycloak.models.UserModel,javax.ws.rs.core.MultivaluedMap" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
+<%@ page import="java.util.List" %>
<%
RealmModel realm = (RealmModel)request.getAttribute(RealmModel.class.getName());
String username = (String)request.getAttribute("username");
diff --git a/examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp b/examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp
index 91657c9..cc5925d 100755
--- a/examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp
@@ -1,4 +1,4 @@
-<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<head>
examples/as7-eap-dev/server/pom.xml 21(+0 -21)
diff --git a/examples/as7-eap-dev/server/pom.xml b/examples/as7-eap-dev/server/pom.xml
index b568d69..4ccbd3e 100755
--- a/examples/as7-eap-dev/server/pom.xml
+++ b/examples/as7-eap-dev/server/pom.xml
@@ -37,11 +37,6 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-model-picketlink</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId>
<version>${project.version}</version>
</dependency>
@@ -66,22 +61,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-idm-simple-schema</artifactId>
- </dependency>
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-config</artifactId>
- </dependency>
- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
diff --git a/examples/as7-eap-dev/server/src/main/java/org/keycloak/example/demo/DemoApplication.java b/examples/as7-eap-dev/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
index 2f512e2..856f355 100755
--- a/examples/as7-eap-dev/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
+++ b/examples/as7-eap-dev/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
@@ -1,11 +1,11 @@
package org.keycloak.example.demo;
import org.jboss.resteasy.jwt.JsonSerialization;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
import org.keycloak.services.resources.KeycloakApplication;
import javax.servlet.ServletContext;
diff --git a/examples/as7-eap-dev/server/src/main/resources/META-INF/persistence.xml b/examples/as7-eap-dev/server/src/main/resources/META-INF/persistence.xml
index cb5a1c3..23f0913 100755
--- a/examples/as7-eap-dev/server/src/main/resources/META-INF/persistence.xml
+++ b/examples/as7-eap-dev/server/src/main/resources/META-INF/persistence.xml
@@ -2,27 +2,25 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
-
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
- <class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
- <class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
+
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.RoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
-
+
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
@@ -30,4 +28,5 @@
</properties>
</persistence-unit>
+
</persistence>
diff --git a/examples/as7-eap-dev/server/src/main/webapp/saas/oauthGrantForm.jsp b/examples/as7-eap-dev/server/src/main/webapp/saas/oauthGrantForm.jsp
index 4bbd6df..d62b00e 100755
--- a/examples/as7-eap-dev/server/src/main/webapp/saas/oauthGrantForm.jsp
+++ b/examples/as7-eap-dev/server/src/main/webapp/saas/oauthGrantForm.jsp
@@ -1,5 +1,6 @@
-<%@ page import="org.keycloak.models.*,org.keycloak.services.resources.*,javax.ws.rs.core.*,java.util.*" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="org.keycloak.models.RealmModel,org.keycloak.models.RoleModel,org.keycloak.models.UserModel,javax.ws.rs.core.MultivaluedMap" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
+<%@ page import="java.util.List" %>
<%
RealmModel realm = (RealmModel)request.getAttribute(RealmModel.class.getName());
String username = (String)request.getAttribute("username");
forms/pom.xml 5(+0 -5)
diff --git a/forms/pom.xml b/forms/pom.xml
index 0af1892..933b9ae 100755
--- a/forms/pom.xml
+++ b/forms/pom.xml
@@ -34,11 +34,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-common</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
diff --git a/forms/src/main/java/org/keycloak/forms/LoginBean.java b/forms/src/main/java/org/keycloak/forms/LoginBean.java
index 9174813..02fc10b 100755
--- a/forms/src/main/java/org/keycloak/forms/LoginBean.java
+++ b/forms/src/main/java/org/keycloak/forms/LoginBean.java
@@ -21,12 +21,11 @@
*/
package org.keycloak.forms;
-import java.util.LinkedList;
-import java.util.List;
+import org.keycloak.forms.model.RequiredCredential;
import javax.ws.rs.core.MultivaluedMap;
-
-import org.keycloak.forms.model.RequiredCredential;
+import java.util.LinkedList;
+import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/forms/src/main/java/org/keycloak/forms/OAuthGrantBean.java b/forms/src/main/java/org/keycloak/forms/OAuthGrantBean.java
old mode 100644
new mode 100755
index ce7bf04..560c37a
--- a/forms/src/main/java/org/keycloak/forms/OAuthGrantBean.java
+++ b/forms/src/main/java/org/keycloak/forms/OAuthGrantBean.java
@@ -21,14 +21,13 @@
*/
package org.keycloak.forms;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.ws.rs.core.MultivaluedMap;
-
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
*/
diff --git a/forms/src/main/java/org/keycloak/forms/RegisterBean.java b/forms/src/main/java/org/keycloak/forms/RegisterBean.java
index cb8c83d..94bb83c 100755
--- a/forms/src/main/java/org/keycloak/forms/RegisterBean.java
+++ b/forms/src/main/java/org/keycloak/forms/RegisterBean.java
@@ -21,11 +21,10 @@
*/
package org.keycloak.forms;
+import javax.ws.rs.core.MultivaluedMap;
import java.util.HashMap;
import java.util.Map;
-import javax.ws.rs.core.MultivaluedMap;
-
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/forms/src/main/java/org/keycloak/forms/SocialBean.java b/forms/src/main/java/org/keycloak/forms/SocialBean.java
old mode 100644
new mode 100755
index 19baaa7..0861b55
--- a/forms/src/main/java/org/keycloak/forms/SocialBean.java
+++ b/forms/src/main/java/org/keycloak/forms/SocialBean.java
@@ -21,15 +21,14 @@
*/
package org.keycloak.forms;
-import java.net.URI;
-import java.util.*;
-
-import javax.imageio.spi.ServiceRegistry;
-import javax.ws.rs.core.UriBuilder;
-
import org.keycloak.forms.model.SocialProvider;
import org.keycloak.services.resources.flows.Urls;
+import javax.ws.rs.core.UriBuilder;
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/forms/src/main/java/org/keycloak/forms/TotpBean.java b/forms/src/main/java/org/keycloak/forms/TotpBean.java
old mode 100644
new mode 100755
index a283c2e..5ce40bc
--- a/forms/src/main/java/org/keycloak/forms/TotpBean.java
+++ b/forms/src/main/java/org/keycloak/forms/TotpBean.java
@@ -21,11 +21,12 @@
*/
package org.keycloak.forms;
+import org.keycloak.models.utils.Base32;
+
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Random;
-import org.picketlink.common.util.Base32;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/forms/src/main/java/org/keycloak/forms/UrlBean.java b/forms/src/main/java/org/keycloak/forms/UrlBean.java
index 8d25c3d..49635a0 100755
--- a/forms/src/main/java/org/keycloak/forms/UrlBean.java
+++ b/forms/src/main/java/org/keycloak/forms/UrlBean.java
@@ -21,10 +21,10 @@
*/
package org.keycloak.forms;
-import java.net.URI;
-
import org.keycloak.services.resources.flows.Urls;
+import java.net.URI;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/forms/src/main/java/org/keycloak/service/FormServiceImpl.java b/forms/src/main/java/org/keycloak/service/FormServiceImpl.java
old mode 100644
new mode 100755
index 6ec433e..b7b914c
--- a/forms/src/main/java/org/keycloak/service/FormServiceImpl.java
+++ b/forms/src/main/java/org/keycloak/service/FormServiceImpl.java
@@ -21,19 +21,12 @@
*/
package org.keycloak.service;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ResourceBundle;
-
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.forms.MessageBean;
import org.keycloak.forms.LoginBean;
+import org.keycloak.forms.MessageBean;
import org.keycloak.forms.OAuthGrantBean;
import org.keycloak.forms.RealmBean;
import org.keycloak.forms.RegisterBean;
@@ -45,6 +38,13 @@ import org.keycloak.forms.UserBean;
import org.keycloak.services.FormService;
import org.keycloak.services.resources.flows.Pages;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
/**
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
*/
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
index 28cd21c..1e01298 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
@@ -71,7 +71,7 @@ body {
width: auto;
position: relative;
}
-.rcue-login-register .background-area .separator .section,
+.rcue-login-register .background-area .section,
.rcue-login-register .background-area .social .section {
padding-top: 1.5em;
padding-bottom: 1.5em;
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-reset-password.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-reset-password.ftl
index 96f8795..7a045e5 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-reset-password.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-reset-password.ftl
@@ -1,5 +1,5 @@
<#import "template-login-action.ftl" as layout>
-<@layout.registrationLayout bodyClass="reset"; section>
+<@layout.registrationLayout bodyClass="reset" isSeparator=true forceSeparator=true; section>
<#if section = "title">
${rb.getString('emailForgotHeader')}
@@ -23,6 +23,6 @@
</form>
</div>
<#elseif section = "info" >
- <p><a href="#">« Back to Login</a></p>
+ <p><a href="${url.loginUrl}">« Back to Login</a></p>
</#if>
</@layout.registrationLayout>
\ No newline at end of file
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-password.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-password.ftl
index 74142e0..955d4df 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-password.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-password.ftl
@@ -1,5 +1,5 @@
<#import "template-login-action.ftl" as layout>
-<@layout.registrationLayout bodyClass="reset"; section>
+<@layout.registrationLayout bodyClass="reset" isSeparator=false forceSeparator=true; section>
<#if section = "title">
${rb.getString('emailUpdateHeader')}
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-profile.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-profile.ftl
index 32bdd23..ca707a5 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-profile.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-update-profile.ftl
@@ -1,5 +1,5 @@
<#import "template-login-action.ftl" as layout>
-<@layout.registrationLayout bodyClass=""; section>
+<@layout.registrationLayout bodyClass="" isSeparator=false forceSeparator=true; section>
<#if section = "title">
Update Account Information
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-verify-email.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-verify-email.ftl
index 0832666..cc83a85 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-verify-email.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-verify-email.ftl
@@ -1,5 +1,5 @@
<#import "template-login-action.ftl" as layout>
-<@layout.registrationLayout bodyClass="email"; section>
+<@layout.registrationLayout bodyClass="email" isSeparator=false forceSeparator=true; section>
<#if section = "title">
Email verification
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login.ftl
index acbb082..10c668a 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login.ftl
@@ -1,4 +1,4 @@
-<#macro registrationLayout bodyClass>
+<#macro registrationLayout bodyClass isSeparator=false forceSeparator=false>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
@@ -7,6 +7,7 @@
<title>
<#nested "title">
</title>
+ <link rel="icon" href="${template.formsPath}/theme/${template.theme}/img/favicon.ico">
<link href="${template.themeConfig.styles}" rel="stylesheet" />
<style type="text/css">
body.rcue-login-register {
@@ -18,7 +19,7 @@
<body class="rcue-login-register ${bodyClass}">
<#if (template.themeConfig.logo)?has_content>
<h1>
- <a href="#" title="Go to the login page"><img src="${template.themeConfig.logo}" alt="Red Hat Logo" /></a>
+ <a href="${url.loginUrl}" title="Go to the login page"><img src="${template.themeConfig.logo}" alt="Red Hat Logo" /></a>
</h1>
</#if>
@@ -28,7 +29,12 @@
</h2>
<div class="background-area">
- <div class="form-area ${(realm.social)?string('social','')} clearfix">
+ <#if !forceSeparator && realm?has_content>
+ <#assign drawSeparator = realm.registrationAllowed>
+ <#else>
+ <#assign drawSeparator = isSeparator>
+ </#if>
+ <div class="form-area ${(realm.social && bodyClass != "register")?string('social','')} ${(drawSeparator)?string('separator','')} clearfix">
<div class="section app-form">
<h3>Application login area</h3>
<#if message?has_content && message.error>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login-action.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login-action.ftl
index 982b31f..f3113dc 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login-action.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-login-action.ftl
@@ -1,4 +1,4 @@
-<#macro registrationLayout bodyClass isErrorPage=false>
+<#macro registrationLayout bodyClass isErrorPage=false isSeparator=false forceSeparator=false>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
@@ -7,6 +7,7 @@
<title>
<#nested "title">
</title>
+ <link rel="icon" href="${template.formsPath}/theme/${template.theme}/img/favicon.ico">
<link href="${template.themeConfig.styles}" rel="stylesheet" />
<style type="text/css">
body.rcue-login-register {
@@ -25,7 +26,7 @@
</div>
<#if (template.themeConfig.logo)?has_content>
<h1>
- <a href="#" title="Go to the login page"><img src="${template.themeConfig.logo}" alt="Red Hat Logo" /></a>
+ <a href="${url.loginUrl}" title="Go to the login page"><img src="${template.themeConfig.logo}" alt="Red Hat Logo" /></a>
</h1>
</#if>
@@ -35,7 +36,12 @@
</h2>
<div class="background-area">
- <div class="form-area clearfix">
+ <#if !forceSeparator && realm?has_content>
+ <#assign drawSeparator = realm.registrationAllowed>
+ <#else>
+ <#assign drawSeparator = isSeparator>
+ </#if>
+ <div class="form-area clearfix ${(drawSeparator)?string('separator','')}">
<div class="section app-form">
<#if !isErrorPage && message?has_content>
<#if message.error>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
index 61e24a8..4a45d93 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
@@ -4,8 +4,7 @@
<head>
<meta charset="utf-8">
<title>Edit Account - <#nested "title"></title>
- <!-- TODO replace with actual logo once
- <link rel="icon" href="img/favicon.ico">
+ <link rel="icon" href="${template.formsPath}/theme/${template.theme}/img/favicon.ico">
<!-- Frameworks -->
<link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/reset.css">
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
index f151e15..5d2d7d4 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
@@ -7,7 +7,6 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.as7.config.ManagedResourceConfig;
import org.keycloak.representations.SkeletonKeyToken;
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
index 655dd46..3aada8b 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
@@ -5,7 +5,6 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
index cc6a2d6..29b1e60 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
@@ -13,7 +13,6 @@ import org.keycloak.PemUtils;
import org.keycloak.ResourceMetadata;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
-import javax.ws.rs.client.WebTarget;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
diff --git a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
index 9a346f2..e5374b8 100755
--- a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
@@ -1,7 +1,6 @@
package org.keycloak.models;
import java.util.List;
-import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java
index 18adf63..b02c9c2 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -15,4 +15,6 @@ public interface Constants {
String ACCOUNT_APPLICATION = "Account";
String ACCOUNT_PROFILE_ROLE = "view-profile";
String ACCOUNT_MANAGE_ROLE = "manage-account";
+
+ String ACCOUNT_MANAGEMENT_APPLICATION = "Account Management";
}
diff --git a/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java b/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
index 2b25f46..622500c 100755
--- a/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
@@ -1,7 +1,5 @@
package org.keycloak.models;
-import org.keycloak.models.UserModel;
-
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -10,8 +8,4 @@ public interface OAuthClientModel {
String getId();
UserModel getOAuthAgent();
-
- String getBaseUrl();
-
- void setBaseUrl(String base);
}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 2de3e58..3b0b149 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -2,7 +2,6 @@ package org.keycloak.models;
import java.security.PrivateKey;
import java.security.PublicKey;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -138,11 +137,11 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
List<OAuthClientModel> getOAuthClients();
- HashMap<String, String> getSmtpConfig();
+ Map<String, String> getSmtpConfig();
- void setSmtpConfig(HashMap<String, String> smtpConfig);
+ void setSmtpConfig(Map<String, String> smtpConfig);
- HashMap<String, String> getSocialConfig();
+ Map<String, String> getSocialConfig();
- void setSocialConfig(HashMap<String, String> socialConfig);
+ void setSocialConfig(Map<String, String> socialConfig);
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/Base32.java b/model/api/src/main/java/org/keycloak/models/utils/Base32.java
new file mode 100755
index 0000000..aef4422
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/Base32.java
@@ -0,0 +1,113 @@
+package org.keycloak.models.utils;
+
+
+/* (PD) 2006 The Bitzi Corporation
+ * Please see http://bitzi.com/publicdomain for more info.
+ *
+ * $Id: Base32.java,v 1.2 2006/07/14 04:58:39 gojomo Exp $
+ */
+
+/**
+ * Base32 - encodes and decodes RFC3548 Base32 (see http://www.faqs.org/rfcs/rfc3548.html )
+ *
+ * @author Robert Kaye
+ * @author Gordon Mohr
+ */
+public class Base32 {
+ private static final String base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+ private static final int[] base32Lookup = { 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ /**
+ * Encodes byte array to Base32 String.
+ *
+ * @param bytes Bytes to encode.
+ * @return Encoded byte array <code>bytes</code> as a String.
+ *
+ */
+ public static String encode(final byte[] bytes) {
+ int i = 0, index = 0, digit = 0;
+ int currByte, nextByte;
+ StringBuffer base32 = new StringBuffer((bytes.length + 7) * 8 / 5);
+
+ while (i < bytes.length) {
+ currByte = (bytes[i] >= 0) ? bytes[i] : (bytes[i] + 256);
+
+ /* Is the current digit going to span a byte boundary? */
+ if (index > 3) {
+ if ((i + 1) < bytes.length) {
+ nextByte = (bytes[i + 1] >= 0) ? bytes[i + 1] : (bytes[i + 1] + 256);
+ } else {
+ nextByte = 0;
+ }
+
+ digit = currByte & (0xFF >> index);
+ index = (index + 5) % 8;
+ digit <<= index;
+ digit |= nextByte >> (8 - index);
+ i++;
+ } else {
+ digit = (currByte >> (8 - (index + 5))) & 0x1F;
+ index = (index + 5) % 8;
+ if (index == 0)
+ i++;
+ }
+ base32.append(base32Chars.charAt(digit));
+ }
+
+ return base32.toString();
+ }
+
+ /**
+ * Decodes the given Base32 String to a raw byte array.
+ *
+ * @param base32
+ * @return Decoded <code>base32</code> String as a raw byte array.
+ */
+ public static byte[] decode(final String base32) {
+ int i, index, lookup, offset, digit;
+ byte[] bytes = new byte[base32.length() * 5 / 8];
+
+ for (i = 0, index = 0, offset = 0; i < base32.length(); i++) {
+ lookup = base32.charAt(i) - '0';
+
+ /* Skip chars outside the lookup table */
+ if (lookup < 0 || lookup >= base32Lookup.length) {
+ continue;
+ }
+
+ digit = base32Lookup[lookup];
+
+ /* If this digit is not in the table, ignore it */
+ if (digit == 0xFF) {
+ continue;
+ }
+
+ if (index <= 3) {
+ index = (index + 5) % 8;
+ if (index == 0) {
+ bytes[offset] |= digit;
+ offset++;
+ if (offset >= bytes.length)
+ break;
+ } else {
+ bytes[offset] |= digit << (8 - index);
+ }
+ } else {
+ index = (index + 5) % 8;
+ bytes[offset] |= (digit >>> index);
+ offset++;
+
+ if (offset >= bytes.length) {
+ break;
+ }
+ bytes[offset] |= digit << (8 - index);
+ }
+ }
+ return bytes;
+ }
+
+}
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/utils/Base64.java b/model/api/src/main/java/org/keycloak/models/utils/Base64.java
new file mode 100755
index 0000000..2fa912b
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/Base64.java
@@ -0,0 +1,2282 @@
+package org.keycloak.models.utils;
+
+/**
+ * <p>Encodes and decodes to and from Base64 notation.</p>
+ * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
+ * <p/>
+ * <p>Example:</p>
+ * <p/>
+ * <code>String encoded = Base64.encode( myByteArray );</code>
+ * <br />
+ * <code>byte[] myByteArray = Base64.decode( encoded );</code>
+ * <p/>
+ * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass
+ * several pieces of information to the encoder. In the "higher level" methods such as
+ * encodeBytes( bytes, options ) the options parameter can be used to indicate such
+ * things as first gzipping the bytes before encoding them, not inserting linefeeds,
+ * and encoding using the URL-safe and Ordered dialects.</p>
+ * <p/>
+ * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
+ * Section 2.1, implementations should not add line feeds unless explicitly told
+ * to do so. I've got Base64 set to this behavior now, although earlier versions
+ * broke lines by default.</p>
+ * <p/>
+ * <p>The constants defined in Base64 can be OR-ed together to combine options, so you
+ * might make a call like this:</p>
+ * <p/>
+ * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
+ * <p>to compress the data before encoding it and then making the output have newline characters.</p>
+ * <p>Also...</p>
+ * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
+ * <p/>
+ * <p/>
+ * <p/>
+ * <p>
+ * Change Log:
+ * </p>
+ * <ul>
+ * <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
+ * value 01111111, which is an invalid base 64 character but should not
+ * throw an ArrayIndexOutOfBoundsException either. Led to discovery of
+ * mishandling (or potential for better handling) of other bad input
+ * characters. You should now get an IOException if you try decoding
+ * something that has bad characters in it.</li>
+ * <li>v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded
+ * string ended in the last column; the buffer was not properly shrunk and
+ * contained an extra (null) byte that made it into the string.</li>
+ * <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
+ * was wrong for files of size 31, 34, and 37 bytes.</li>
+ * <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
+ * the Base64.OutputStream closed the Base64 encoding (by padding with equals
+ * signs) too soon. Also added an option to suppress the automatic decoding
+ * of gzipped streams. Also added experimental support for specifying a
+ * class loader when using the
+ * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}
+ * method.</li>
+ * <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
+ * footprint with its CharEncoders and so forth. Fixed some javadocs that were
+ * inconsistent. Removed imports and specified things like java.io.IOException
+ * explicitly inline.</li>
+ * <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
+ * final encoded data will be so that the code doesn't have to create two output
+ * arrays: an oversized initial one and then a final, exact-sized one. Big win
+ * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
+ * using the gzip options which uses a different mechanism with streams and stuff).</li>
+ * <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
+ * similar helper methods to be more efficient with memory by not returning a
+ * String but just a byte array.</li>
+ * <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
+ * and bug fixes queued up and finally executed. Thanks to everyone who sent
+ * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
+ * Much bad coding was cleaned up including throwing exceptions where necessary
+ * instead of returning null values or something similar. Here are some changes
+ * that may affect you:
+ * <ul>
+ * <li><em>Does not break lines, by default.</em> This is to keep in compliance with
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
+ * <li><em>Throws exceptions instead of returning null values.</em> Because some operations
+ * (especially those that may permit the GZIP option) use IO streams, there
+ * is a possiblity of an java.io.IOException being thrown. After some discussion and
+ * thought, I've changed the behavior of the methods to throw java.io.IOExceptions
+ * rather than return null if ever there's an error. I think this is more
+ * appropriate, though it will require some changes to your code. Sorry,
+ * it should have been done this way to begin with.</li>
+ * <li><em>Removed all references to System.out, System.err, and the like.</em>
+ * Shame on me. All I can say is sorry they were ever there.</li>
+ * <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
+ * such as when passed arrays are null or offsets are invalid.</li>
+ * <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
+ * This was especially annoying before for people who were thorough in their
+ * own projects and then had gobs of javadoc warnings on this file.</li>
+ * </ul>
+ * <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
+ * when using very small files (~< 40 bytes).</li>
+ * <li>v2.2 - Added some helper methods for encoding/decoding directly from
+ * one file to the next. Also added a main() method to support command line
+ * encoding/decoding from one file to the next. Also added these Base64 dialects:
+ * <ol>
+ * <li>The default is RFC3548 format.</li>
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
+ * URL and file name friendly format as described in Section 4 of RFC3548.
+ * http://www.faqs.org/rfcs/rfc3548.html</li>
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
+ * URL and file name friendly format that preserves lexical ordering as described
+ * in http://www.faqs.org/qa/rfcc-1940.html</li>
+ * </ol>
+ * Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
+ * for contributing the new Base64 dialects.
+ * </li>
+ * <p/>
+ * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
+ * some convenience methods for reading and writing to and from files.</li>
+ * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
+ * with other encodings (like EBCDIC).</li>
+ * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
+ * encoded data was a single byte.</li>
+ * <li>v2.0 - I got rid of methods that used booleans to set options.
+ * Now everything is more consolidated and cleaner. The code now detects
+ * when data that's being decoded is gzip-compressed and will decompress it
+ * automatically. Generally things are cleaner. You'll probably have to
+ * change some method calls that you were making to support the new
+ * options format (<tt>int</tt>s that you "OR" together).</li>
+ * <li>v1.5.1 - Fixed bug when decompressing and decoding to a
+ * byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
+ * Added the ability to "suspend" encoding in the Output Stream so
+ * you can turn on and off the encoding if you need to embed base64
+ * data in an otherwise "normal" stream (like an XML file).</li>
+ * <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
+ * This helps when using GZIP streams.
+ * Added the ability to GZip-compress objects before encoding them.</li>
+ * <li>v1.4 - Added helper methods to read/write files.</li>
+ * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
+ * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
+ * where last buffer being read, if not completely full, was not returned.</li>
+ * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
+ * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
+ * </ul>
+ * <p/>
+ * <p>
+ * I am placing this code in the Public Domain. Do with it as you will.
+ * This software comes with no guarantees or warranties but with
+ * plenty of well-wishing instead!
+ * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
+ * periodically to check for updates or to contribute improvements.
+ * </p>
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 2.3.7
+ */
+public class Base64
+{
+
+/* ******** P U B L I C F I E L D S ******** */
+
+
+ /**
+ * No options specified. Value is zero.
+ */
+ public final static int NO_OPTIONS = 0;
+
+ /**
+ * Specify encoding in first bit. Value is one.
+ */
+ public final static int ENCODE = 1;
+
+
+ /**
+ * Specify decoding in first bit. Value is zero.
+ */
+ public final static int DECODE = 0;
+
+
+ /**
+ * Specify that data should be gzip-compressed in second bit. Value is two.
+ */
+ public final static int GZIP = 2;
+
+ /**
+ * Specify that gzipped data should <em>not</em> be automatically gunzipped.
+ */
+ public final static int DONT_GUNZIP = 4;
+
+
+ /**
+ * Do break lines when encoding. Value is 8.
+ */
+ public final static int DO_BREAK_LINES = 8;
+
+ /**
+ * Encode using Base64-like encoding that is URL- and Filename-safe as described
+ * in Section 4 of RFC3548:
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+ * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
+ * or at the very least should not be called Base64 without also specifying that is
+ * was encoded using the URL- and Filename-safe dialect.
+ */
+ public final static int URL_SAFE = 16;
+
+
+ /**
+ * Encode using the special "ordered" dialect of Base64 described here:
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+ */
+ public final static int ORDERED = 32;
+
+
+/* ******** P R I V A T E F I E L D S ******** */
+
+
+ /**
+ * Maximum line length (76) of Base64 output.
+ */
+ private final static int MAX_LINE_LENGTH = 76;
+
+
+ /**
+ * The equals sign (=) as a byte.
+ */
+ private final static byte EQUALS_SIGN = (byte) '=';
+
+
+ /**
+ * The new line character (\n) as a byte.
+ */
+ private final static byte NEW_LINE = (byte) '\n';
+
+
+ /**
+ * Preferred encoding.
+ */
+ private final static String PREFERRED_ENCODING = "US-ASCII";
+
+
+ private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
+ private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
+
+
+/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * The 64 valid Base64 values.
+ */
+ /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
+ private final static byte[] _STANDARD_ALPHABET = {
+ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
+ (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
+ (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
+ (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
+ (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
+ (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
+ (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'
+ };
+
+
+ /**
+ * Translates a Base64 value to either its 6-bit reconstruction value
+ * or a negative number indicating some other meaning.
+ */
+ private final static byte[] _STANDARD_DECODABET = {
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ 62, // Plus sign at decimal 43
+ -9, -9, -9, // Decimal 44 - 46
+ 63, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
+ -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+
+/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+ * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
+ */
+ private final static byte[] _URL_SAFE_ALPHABET = {
+ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
+ (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
+ (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
+ (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
+ (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
+ (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
+ (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_'
+ };
+
+ /**
+ * Used in decoding URL- and Filename-safe dialects of Base64.
+ */
+ private final static byte[] _URL_SAFE_DECODABET = {
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 62, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 63, // Underscore at decimal 95
+ -9, // Decimal 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+
+/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * I don't get the point of this technique, but someone requested it,
+ * and it is described here:
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+ */
+ private final static byte[] _ORDERED_ALPHABET = {
+ (byte) '-',
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
+ (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
+ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
+ (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
+ (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
+ (byte) '_',
+ (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
+ (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
+ (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z'
+ };
+
+ /**
+ * Used in decoding the "ordered" dialect of Base64.
+ */
+ private final static byte[] _ORDERED_DECODABET = {
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 0, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M'
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 37, // Underscore at decimal 95
+ -9, // Decimal 96
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm'
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+
+/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
+
+
+ /**
+ * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
+ * the options specified.
+ * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
+ * in which case one of them will be picked, though there is
+ * no guarantee as to which one will be picked.
+ */
+ private final static byte[] getAlphabet(int options)
+ {
+ if ((options & URL_SAFE) == URL_SAFE)
+ {
+ return _URL_SAFE_ALPHABET;
+ }
+ else if ((options & ORDERED) == ORDERED)
+ {
+ return _ORDERED_ALPHABET;
+ }
+ else
+ {
+ return _STANDARD_ALPHABET;
+ }
+ } // end getAlphabet
+
+
+ /**
+ * Returns one of the _SOMETHING_DECODABET byte arrays depending on
+ * the options specified.
+ * It's possible, though silly, to specify ORDERED and URL_SAFE
+ * in which case one of them will be picked, though there is
+ * no guarantee as to which one will be picked.
+ */
+ private final static byte[] getDecodabet(int options)
+ {
+ if ((options & URL_SAFE) == URL_SAFE)
+ {
+ return _URL_SAFE_DECODABET;
+ }
+ else if ((options & ORDERED) == ORDERED)
+ {
+ return _ORDERED_DECODABET;
+ }
+ else
+ {
+ return _STANDARD_DECODABET;
+ }
+ } // end getAlphabet
+
+
+ /**
+ * Defeats instantiation.
+ */
+ private Base64()
+ {
+ }
+
+
+/* ******** E N C O D I N G M E T H O D S ******** */
+
+
+ /**
+ * Encodes up to the first three bytes of array <var>threeBytes</var>
+ * and returns a four-byte array in Base64 notation.
+ * The actual number of significant bytes in your array is
+ * given by <var>numSigBytes</var>.
+ * The array <var>threeBytes</var> needs only be as big as
+ * <var>numSigBytes</var>.
+ * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
+ *
+ * @param b4 A reusable byte array to reduce array instantiation
+ * @param threeBytes the array to convert
+ * @param numSigBytes the number of significant bytes in your array
+ * @return four byte array in Base64 notation.
+ * @since 1.5.1
+ */
+ private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes, int options)
+ {
+ encode3to4(threeBytes, 0, numSigBytes, b4, 0, options);
+ return b4;
+ } // end encode3to4
+
+
+ /**
+ * <p>Encodes up to three bytes of the array <var>source</var>
+ * and writes the resulting four Base64 bytes to <var>destination</var>.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * <var>srcOffset</var> and <var>destOffset</var>.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate <var>srcOffset</var> + 3 for
+ * the <var>source</var> array or <var>destOffset</var> + 4 for
+ * the <var>destination</var> array.
+ * The actual number of significant bytes in your array is
+ * given by <var>numSigBytes</var>.</p>
+ * <p>This is the lowest level of the encoding methods with
+ * all possible parameters.</p>
+ *
+ * @param source the array to convert
+ * @param srcOffset the index where conversion begins
+ * @param numSigBytes the number of significant bytes in your array
+ * @param destination the array to hold the conversion
+ * @param destOffset the index where output will be put
+ * @return the <var>destination</var> array
+ * @since 1.3
+ */
+ private static byte[] encode3to4(
+ byte[] source, int srcOffset, int numSigBytes,
+ byte[] destination, int destOffset, int options)
+ {
+
+ byte[] ALPHABET = getAlphabet(options);
+
+ // 1 2 3
+ // 01234567890123456789012345678901 Bit position
+ // --------000000001111111122222222 Array position from threeBytes
+ // --------| || || || | Six bit groups to index ALPHABET
+ // >>18 >>12 >> 6 >> 0 Right shift necessary
+ // 0x3f 0x3f 0x3f Additional AND
+
+ // Create buffer with zero-padding if there are only one or two
+ // significant bytes passed in the array.
+ // We have to shift left 24 in order to flush out the 1's that appear
+ // when Java treats a value as negative that is cast from a byte to an int.
+ int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
+ | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
+ | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
+
+ switch (numSigBytes)
+ {
+ case 3:
+ destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+ destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+ destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
+ destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
+ return destination;
+
+ case 2:
+ destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+ destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+ destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
+ destination[destOffset + 3] = EQUALS_SIGN;
+ return destination;
+
+ case 1:
+ destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+ destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+ destination[destOffset + 2] = EQUALS_SIGN;
+ destination[destOffset + 3] = EQUALS_SIGN;
+ return destination;
+
+ default:
+ return destination;
+ } // end switch
+ } // end encode3to4
+
+
+ /**
+ * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
+ * writing it to the <code>encoded</code> ByteBuffer.
+ * This is an experimental feature. Currently it does not
+ * pass along any options (such as {@link #DO_BREAK_LINES}
+ * or {@link #GZIP}.
+ *
+ * @param raw input buffer
+ * @param encoded output buffer
+ * @since 2.3
+ */
+ public static void encode(java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded)
+ {
+ byte[] raw3 = new byte[3];
+ byte[] enc4 = new byte[4];
+
+ while (raw.hasRemaining())
+ {
+ int rem = Math.min(3, raw.remaining());
+ raw.get(raw3, 0, rem);
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
+ encoded.put(enc4);
+ } // end input remaining
+ }
+
+
+ /**
+ * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
+ * writing it to the <code>encoded</code> CharBuffer.
+ * This is an experimental feature. Currently it does not
+ * pass along any options (such as {@link #DO_BREAK_LINES}
+ * or {@link #GZIP}.
+ *
+ * @param raw input buffer
+ * @param encoded output buffer
+ * @since 2.3
+ */
+ public static void encode(java.nio.ByteBuffer raw, java.nio.CharBuffer encoded)
+ {
+ byte[] raw3 = new byte[3];
+ byte[] enc4 = new byte[4];
+
+ while (raw.hasRemaining())
+ {
+ int rem = Math.min(3, raw.remaining());
+ raw.get(raw3, 0, rem);
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
+ for (int i = 0; i < 4; i++)
+ {
+ encoded.put((char) (enc4[i] & 0xFF));
+ }
+ } // end input remaining
+ }
+
+
+ /**
+ * Serializes an object and returns the Base64-encoded
+ * version of that serialized object.
+ * <p/>
+ * <p>As of v 2.3, if the object
+ * cannot be serialized or there is another error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned a null value, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ * <p/>
+ * The object is not GZip-compressed before being encoded.
+ *
+ * @param serializableObject The object to encode
+ * @return The Base64-encoded object
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if serializedObject is null
+ * @since 1.4
+ */
+ public static String encodeObject(java.io.Serializable serializableObject)
+ throws java.io.IOException
+ {
+ return encodeObject(serializableObject, NO_OPTIONS);
+ } // end encodeObject
+
+
+ /**
+ * Serializes an object and returns the Base64-encoded
+ * version of that serialized object.
+ * <p/>
+ * <p>As of v 2.3, if the object
+ * cannot be serialized or there is another error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned a null value, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ * <p/>
+ * The object is not GZip-compressed before being encoded.
+ * <p/>
+ * Example options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DO_BREAK_LINES: break lines at 76 characters
+ * </pre>
+ * <p/>
+ * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
+ * <p/>
+ * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+ *
+ * @param serializableObject The object to encode
+ * @param options Specified options
+ * @return The Base64-encoded object
+ * @throws java.io.IOException if there is an error
+ * @see Base64#GZIP
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeObject(java.io.Serializable serializableObject, int options)
+ throws java.io.IOException
+ {
+
+ if (serializableObject == null)
+ {
+ throw new NullPointerException("Cannot serialize a null object.");
+ } // end if: null
+
+ // Streams
+ java.io.ByteArrayOutputStream baos = null;
+ java.io.OutputStream b64os = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ java.io.ObjectOutputStream oos = null;
+
+
+ try
+ {
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream(baos, ENCODE | options);
+ if ((options & GZIP) != 0)
+ {
+ // Gzip
+ gzos = new java.util.zip.GZIPOutputStream(b64os);
+ oos = new java.io.ObjectOutputStream(gzos);
+ }
+ else
+ {
+ // Not gzipped
+ oos = new java.io.ObjectOutputStream(b64os);
+ }
+ oos.writeObject(serializableObject);
+ } // end try
+ catch (java.io.IOException e)
+ {
+ // Catch it and then throw it immediately so that
+ // the finally{} block is called for cleanup.
+ throw e;
+ } // end catch
+ finally
+ {
+ try
+ { oos.close(); }
+ catch (Exception e)
+ {}
+ try
+ { gzos.close(); }
+ catch (Exception e)
+ {}
+ try
+ { b64os.close(); }
+ catch (Exception e)
+ {}
+ try
+ { baos.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String(baos.toByteArray(), PREFERRED_ENCODING);
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ // Fall back to some Java default
+ return new String(baos.toByteArray());
+ } // end catch
+
+ } // end encode
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @return The data in Base64-encoded form
+ * @throws NullPointerException if source array is null
+ * @since 1.4
+ */
+ public static String encodeBytes(byte[] source)
+ {
+ // Since we're not going to have the GZIP encoding turned on,
+ // we're not going to have an java.io.IOException thrown, so
+ // we should not force the user to have to catch it.
+ String encoded = null;
+ try
+ {
+ encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
+ }
+ catch (java.io.IOException ex)
+ {
+ assert false : ex.getMessage();
+ } // end catch
+ assert encoded != null;
+ return encoded;
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * <p>
+ * Example options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DO_BREAK_LINES: break lines at 76 characters
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+ * <p/>
+ * <p/>
+ * <p>As of v 2.3, if there is an error with the GZIP stream,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned a null value, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param source The data to convert
+ * @param options Specified options
+ * @return The Base64-encoded data as a String
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if source array is null
+ * @see Base64#GZIP
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes(byte[] source, int options) throws java.io.IOException
+ {
+ return encodeBytes(source, 0, source.length, options);
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ * <p/>
+ * <p>As of v 2.3, if there is an error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned a null value, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @return The Base64-encoded data as a String
+ * @throws NullPointerException if source array is null
+ * @throws IllegalArgumentException if source array, offset, or length are invalid
+ * @since 1.4
+ */
+ public static String encodeBytes(byte[] source, int off, int len)
+ {
+ // Since we're not going to have the GZIP encoding turned on,
+ // we're not going to have an java.io.IOException thrown, so
+ // we should not force the user to have to catch it.
+ String encoded = null;
+ try
+ {
+ encoded = encodeBytes(source, off, len, NO_OPTIONS);
+ }
+ catch (java.io.IOException ex)
+ {
+ assert false : ex.getMessage();
+ } // end catch
+ assert encoded != null;
+ return encoded;
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * <p>
+ * Example options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DO_BREAK_LINES: break lines at 76 characters
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+ * <p/>
+ * <p/>
+ * <p>As of v 2.3, if there is an error with the GZIP stream,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned a null value, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @param options Specified options
+ * @return The Base64-encoded data as a String
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if source array is null
+ * @throws IllegalArgumentException if source array, offset, or length are invalid
+ * @see Base64#GZIP
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes(byte[] source, int off, int len, int options) throws java.io.IOException
+ {
+ byte[] encoded = encodeBytesToBytes(source, off, len, options);
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String(encoded, PREFERRED_ENCODING);
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String(encoded);
+ } // end catch
+
+ } // end encodeBytes
+
+
+ /**
+ * Similar to {@link #encodeBytes(byte[])} but returns
+ * a byte array instead of instantiating a String. This is more efficient
+ * if you're working with I/O streams and have large data sets to encode.
+ *
+ * @param source The data to convert
+ * @return The Base64-encoded data as a byte[] (of ASCII characters)
+ * @throws NullPointerException if source array is null
+ * @since 2.3.1
+ */
+ public static byte[] encodeBytesToBytes(byte[] source)
+ {
+ byte[] encoded = null;
+ try
+ {
+ encoded = encodeBytesToBytes(source, 0, source.length, Base64.NO_OPTIONS);
+ }
+ catch (java.io.IOException ex)
+ {
+ assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
+ }
+ return encoded;
+ }
+
+
+ /**
+ * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
+ * a byte array instead of instantiating a String. This is more efficient
+ * if you're working with I/O streams and have large data sets to encode.
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @param options Specified options
+ * @return The Base64-encoded data as a String
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if source array is null
+ * @throws IllegalArgumentException if source array, offset, or length are invalid
+ * @see Base64#GZIP
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.3.1
+ */
+ public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) throws java.io.IOException
+ {
+
+ if (source == null)
+ {
+ throw new NullPointerException("Cannot serialize a null array.");
+ } // end if: null
+
+ if (off < 0)
+ {
+ throw new IllegalArgumentException("Cannot have negative offset: " + off);
+ } // end if: off < 0
+
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Cannot have length offset: " + len);
+ } // end if: len < 0
+
+ if (off + len > source.length)
+ {
+ throw new IllegalArgumentException(
+ String.format("Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
+ } // end if: off < 0
+
+
+ // Compress?
+ if ((options & GZIP) != 0)
+ {
+ java.io.ByteArrayOutputStream baos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ Base64.OutputStream b64os = null;
+
+ try
+ {
+ // GZip -> Base64 -> ByteArray
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream(baos, ENCODE | options);
+ gzos = new java.util.zip.GZIPOutputStream(b64os);
+
+ gzos.write(source, off, len);
+ gzos.close();
+ } // end try
+ catch (java.io.IOException e)
+ {
+ // Catch it and then throw it immediately so that
+ // the finally{} block is called for cleanup.
+ throw e;
+ } // end catch
+ finally
+ {
+ try
+ { gzos.close(); }
+ catch (Exception e)
+ {}
+ try
+ { b64os.close(); }
+ catch (Exception e)
+ {}
+ try
+ { baos.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ return baos.toByteArray();
+ } // end if: compress
+
+ // Else, don't compress. Better not to use streams at all then.
+ else
+ {
+ boolean breakLines = (options & DO_BREAK_LINES) != 0;
+
+ //int len43 = len * 4 / 3;
+ //byte[] outBuff = new byte[ ( len43 ) // Main 4:3
+ // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
+ // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+ // Try to determine more precisely how big the array needs to be.
+ // If we get it right, we don't have to do an array copy, and
+ // we save a bunch of memory.
+ int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed for actual encoding
+ if (breakLines)
+ {
+ encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
+ }
+ byte[] outBuff = new byte[encLen];
+
+
+ int d = 0;
+ int e = 0;
+ int len2 = len - 2;
+ int lineLength = 0;
+ for (; d < len2; d += 3, e += 4)
+ {
+ encode3to4(source, d + off, 3, outBuff, e, options);
+
+ lineLength += 4;
+ if (breakLines && lineLength >= MAX_LINE_LENGTH)
+ {
+ outBuff[e + 4] = NEW_LINE;
+ e++;
+ lineLength = 0;
+ } // end if: end of line
+ } // en dfor: each piece of array
+
+ if (d < len)
+ {
+ encode3to4(source, d + off, len - d, outBuff, e, options);
+ e += 4;
+ } // end if: some padding needed
+
+
+ // Only resize array if we didn't guess it right.
+ if (e <= outBuff.length - 1)
+ {
+ // If breaking lines and the last byte falls right at
+ // the line length (76 bytes per line), there will be
+ // one extra byte, and the array will need to be resized.
+ // Not too bad of an estimate on array size, I'd say.
+ byte[] finalOut = new byte[e];
+ System.arraycopy(outBuff, 0, finalOut, 0, e);
+ //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
+ return finalOut;
+ }
+ else
+ {
+ //System.err.println("No need to resize array.");
+ return outBuff;
+ }
+
+ } // end else: don't compress
+
+ } // end encodeBytesToBytes
+
+
+/* ******** D E C O D I N G M E T H O D S ******** */
+
+
+ /**
+ * Decodes four bytes from array <var>source</var>
+ * and writes the resulting bytes (up to three of them)
+ * to <var>destination</var>.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * <var>srcOffset</var> and <var>destOffset</var>.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate <var>srcOffset</var> + 4 for
+ * the <var>source</var> array or <var>destOffset</var> + 3 for
+ * the <var>destination</var> array.
+ * This method returns the actual number of bytes that
+ * were converted from the Base64 encoding.
+ * <p>This is the lowest level of the decoding methods with
+ * all possible parameters.</p>
+ *
+ * @param source the array to convert
+ * @param srcOffset the index where conversion begins
+ * @param destination the array to hold the conversion
+ * @param destOffset the index where output will be put
+ * @param options alphabet type is pulled from this (standard, url-safe, ordered)
+ * @return the number of decoded bytes converted
+ * @throws NullPointerException if source or destination arrays are null
+ * @throws IllegalArgumentException if srcOffset or destOffset are invalid
+ * or there is not enough room in the array.
+ * @since 1.3
+ */
+ private static int decode4to3(
+ byte[] source, int srcOffset,
+ byte[] destination, int destOffset, int options)
+ {
+
+ // Lots of error checking and exception throwing
+ if (source == null)
+ {
+ throw new NullPointerException("Source array was null.");
+ } // end if
+ if (destination == null)
+ {
+ throw new NullPointerException("Destination array was null.");
+ } // end if
+ if (srcOffset < 0 || srcOffset + 3 >= source.length)
+ {
+ throw new IllegalArgumentException(String.format(
+ "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset));
+ } // end if
+ if (destOffset < 0 || destOffset + 2 >= destination.length)
+ {
+ throw new IllegalArgumentException(String.format(
+ "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset));
+ } // end if
+
+
+ byte[] DECODABET = getDecodabet(options);
+
+ // Example: Dk==
+ if (source[srcOffset + 2] == EQUALS_SIGN)
+ {
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
+ int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
+ | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
+
+ destination[destOffset] = (byte) (outBuff >>> 16);
+ return 1;
+ }
+
+ // Example: DkL=
+ else if (source[srcOffset + 3] == EQUALS_SIGN)
+ {
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
+ int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
+ | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
+ | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
+
+ destination[destOffset] = (byte) (outBuff >>> 16);
+ destination[destOffset + 1] = (byte) (outBuff >>> 8);
+ return 2;
+ }
+
+ // Example: DkLE
+ else
+ {
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
+ // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
+ int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
+ | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
+ | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6)
+ | ((DECODABET[source[srcOffset + 3]] & 0xFF));
+
+
+ destination[destOffset] = (byte) (outBuff >> 16);
+ destination[destOffset + 1] = (byte) (outBuff >> 8);
+ destination[destOffset + 2] = (byte) (outBuff);
+
+ return 3;
+ }
+ } // end decodeToBytes
+
+
+ /**
+ * Low-level access to decoding ASCII characters in
+ * the form of a byte array. <strong>Ignores GUNZIP option, if
+ * it's set.</strong> This is not generally a recommended method,
+ * although it is used internally as part of the decoding process.
+ * Special case: if len = 0, an empty array is returned. Still,
+ * if you need more speed and reduced memory footprint (and aren't
+ * gzipping), consider this method.
+ *
+ * @param source The Base64 encoded data
+ * @return decoded data
+ * @since 2.3.1
+ */
+ public static byte[] decode(byte[] source)
+ throws java.io.IOException
+ {
+ byte[] decoded = null;
+// try {
+ decoded = decode(source, 0, source.length, Base64.NO_OPTIONS);
+// } catch( java.io.IOException ex ) {
+// assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
+// }
+ return decoded;
+ }
+
+
+ /**
+ * Low-level access to decoding ASCII characters in
+ * the form of a byte array. <strong>Ignores GUNZIP option, if
+ * it's set.</strong> This is not generally a recommended method,
+ * although it is used internally as part of the decoding process.
+ * Special case: if len = 0, an empty array is returned. Still,
+ * if you need more speed and reduced memory footprint (and aren't
+ * gzipping), consider this method.
+ *
+ * @param source The Base64 encoded data
+ * @param off The offset of where to begin decoding
+ * @param len The length of characters to decode
+ * @param options Can specify options such as alphabet type to use
+ * @return decoded data
+ * @throws java.io.IOException If bogus characters exist in source data
+ * @since 1.3
+ */
+ public static byte[] decode(byte[] source, int off, int len, int options)
+ throws java.io.IOException
+ {
+
+ // Lots of error checking and exception throwing
+ if (source == null)
+ {
+ throw new NullPointerException("Cannot decode null source array.");
+ } // end if
+ if (off < 0 || off + len > source.length)
+ {
+ throw new IllegalArgumentException(String.format(
+ "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len));
+ } // end if
+
+ if (len == 0)
+ {
+ return new byte[0];
+ }
+ else if (len < 4)
+ {
+ throw new IllegalArgumentException(
+ "Base64-encoded string must have at least four characters, but length specified was " + len);
+ } // end if
+
+ byte[] DECODABET = getDecodabet(options);
+
+ int len34 = len * 3 / 4; // Estimate on array size
+ byte[] outBuff = new byte[len34]; // Upper limit on size of output
+ int outBuffPosn = 0; // Keep track of where we're writing
+
+ byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
+ int b4Posn = 0; // Keep track of four byte input buffer
+ int i = 0; // Source array counter
+ byte sbiDecode = 0; // Special value from DECODABET
+
+ for (i = off; i < off + len; i++)
+ { // Loop through source
+
+ sbiDecode = DECODABET[source[i] & 0xFF];
+
+ // White space, Equals sign, or legit Base64 character
+ // Note the values such as -5 and -9 in the
+ // DECODABETs at the top of the file.
+ if (sbiDecode >= WHITE_SPACE_ENC)
+ {
+ if (sbiDecode >= EQUALS_SIGN_ENC)
+ {
+ b4[b4Posn++] = source[i]; // Save non-whitespace
+ if (b4Posn > 3)
+ { // Time to decode?
+ outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options);
+ b4Posn = 0;
+
+ // If that was the equals sign, break out of 'for' loop
+ if (source[i] == EQUALS_SIGN)
+ {
+ break;
+ } // end if: equals sign
+ } // end if: quartet built
+ } // end if: equals sign or better
+ } // end if: white space, equals sign or better
+ else
+ {
+ // There's a bad input character in the Base64 stream.
+ throw new java.io.IOException(String.format(
+ "Bad Base64 input character decimal %d in array position %d", ((int) source[i]) & 0xFF, i));
+ } // end else:
+ } // each input character
+
+ byte[] out = new byte[outBuffPosn];
+ System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
+ return out;
+ } // end decode
+
+
+ /**
+ * Decodes data from Base64 notation, automatically
+ * detecting gzip-compressed data and decompressing it.
+ *
+ * @param s the string to decode
+ * @return the decoded data
+ * @throws java.io.IOException If there is a problem
+ * @since 1.4
+ */
+ public static byte[] decode(String s) throws java.io.IOException
+ {
+ return decode(s, NO_OPTIONS);
+ }
+
+
+ /**
+ * Decodes data from Base64 notation, automatically
+ * detecting gzip-compressed data and decompressing it.
+ *
+ * @param s the string to decode
+ * @param options encode options such as URL_SAFE
+ * @return the decoded data
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if <tt>s</tt> is null
+ * @since 1.4
+ */
+ public static byte[] decode(String s, int options) throws java.io.IOException
+ {
+
+ if (s == null)
+ {
+ throw new NullPointerException("Input string was null.");
+ } // end if
+
+ byte[] bytes;
+ try
+ {
+ bytes = s.getBytes(PREFERRED_ENCODING);
+ } // end try
+ catch (java.io.UnsupportedEncodingException uee)
+ {
+ bytes = s.getBytes();
+ } // end catch
+ //</change>
+
+ // Decode
+ bytes = decode(bytes, 0, bytes.length, options);
+
+ // Check to see if it's gzip-compressed
+ // GZIP Magic Two-Byte Number: 0x8b1f (35615)
+ boolean dontGunzip = (options & DONT_GUNZIP) != 0;
+ if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip))
+ {
+
+ int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
+ if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head)
+ {
+ java.io.ByteArrayInputStream bais = null;
+ java.util.zip.GZIPInputStream gzis = null;
+ java.io.ByteArrayOutputStream baos = null;
+ byte[] buffer = new byte[2048];
+ int length = 0;
+
+ try
+ {
+ baos = new java.io.ByteArrayOutputStream();
+ bais = new java.io.ByteArrayInputStream(bytes);
+ gzis = new java.util.zip.GZIPInputStream(bais);
+
+ while ((length = gzis.read(buffer)) >= 0)
+ {
+ baos.write(buffer, 0, length);
+ } // end while: reading input
+
+ // No error? Get new bytes.
+ bytes = baos.toByteArray();
+
+ } // end try
+ catch (java.io.IOException e)
+ {
+ e.printStackTrace();
+ // Just return originally-decoded bytes
+ } // end catch
+ finally
+ {
+ try
+ { baos.close(); }
+ catch (Exception e)
+ {}
+ try
+ { gzis.close(); }
+ catch (Exception e)
+ {}
+ try
+ { bais.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ } // end if: gzipped
+ } // end if: bytes.length >= 2
+
+ return bytes;
+ } // end decode
+
+
+ /**
+ * Attempts to decode Base64 data and deserialize a Java
+ * Object within. Returns <tt>null</tt> if there was an error.
+ *
+ * @param encodedObject The Base64 data to decode
+ * @return The decoded and deserialized object
+ * @throws NullPointerException if encodedObject is null
+ * @throws java.io.IOException if there is a general error
+ * @throws ClassNotFoundException if the decoded object is of a
+ * class that cannot be found by the JVM
+ * @since 1.5
+ */
+ public static Object decodeToObject(String encodedObject)
+ throws java.io.IOException, java.lang.ClassNotFoundException
+ {
+ return decodeToObject(encodedObject, NO_OPTIONS, null);
+ }
+
+
+ /**
+ * Attempts to decode Base64 data and deserialize a Java
+ * Object within. Returns <tt>null</tt> if there was an error.
+ * If <tt>loader</tt> is not null, it will be the class loader
+ * used when deserializing.
+ *
+ * @param encodedObject The Base64 data to decode
+ * @param options Various parameters related to decoding
+ * @param loader Optional class loader to use in deserializing classes.
+ * @return The decoded and deserialized object
+ * @throws NullPointerException if encodedObject is null
+ * @throws java.io.IOException if there is a general error
+ * @throws ClassNotFoundException if the decoded object is of a
+ * class that cannot be found by the JVM
+ * @since 2.3.4
+ */
+ public static Object decodeToObject(
+ String encodedObject, int options, final ClassLoader loader)
+ throws java.io.IOException, java.lang.ClassNotFoundException
+ {
+
+ // Decode and gunzip if necessary
+ byte[] objBytes = decode(encodedObject, options);
+
+ java.io.ByteArrayInputStream bais = null;
+ java.io.ObjectInputStream ois = null;
+ Object obj = null;
+
+ try
+ {
+ bais = new java.io.ByteArrayInputStream(objBytes);
+
+ // If no custom class loader is provided, use Java's builtin OIS.
+ if (loader == null)
+ {
+ ois = new java.io.ObjectInputStream(bais);
+ } // end if: no loader provided
+
+ // Else make a customized object input stream that uses
+ // the provided class loader.
+ else
+ {
+ ois = new java.io.ObjectInputStream(bais)
+ {
+ @Override
+ public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
+ throws java.io.IOException, ClassNotFoundException
+ {
+ Class c = Class.forName(streamClass.getName(), false, loader);
+ if (c == null)
+ {
+ return super.resolveClass(streamClass);
+ }
+ else
+ {
+ return c; // Class loader knows of this class.
+ } // end else: not null
+ } // end resolveClass
+ }; // end ois
+ } // end else: no custom class loader
+
+ obj = ois.readObject();
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and throw in order to execute finally{}
+ } // end catch
+ catch (java.lang.ClassNotFoundException e)
+ {
+ throw e; // Catch and throw in order to execute finally{}
+ } // end catch
+ finally
+ {
+ try
+ { bais.close(); }
+ catch (Exception e)
+ {}
+ try
+ { ois.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ return obj;
+ } // end decodeObject
+
+
+ /**
+ * Convenience method for encoding data to a file.
+ * <p/>
+ * <p>As of v 2.3, if there is a error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned false, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param dataToEncode byte array of data to encode in base64 form
+ * @param filename Filename for saving encoded data
+ * @throws java.io.IOException if there is an error
+ * @throws NullPointerException if dataToEncode is null
+ * @since 2.1
+ */
+ public static void encodeToFile(byte[] dataToEncode, String filename)
+ throws java.io.IOException
+ {
+
+ if (dataToEncode == null)
+ {
+ throw new NullPointerException("Data to encode was null.");
+ } // end iff
+
+ Base64.OutputStream bos = null;
+ try
+ {
+ bos = new Base64.OutputStream(
+ new java.io.FileOutputStream(filename), Base64.ENCODE);
+ bos.write(dataToEncode);
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and throw to execute finally{} block
+ } // end catch: java.io.IOException
+ finally
+ {
+ try
+ { bos.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ } // end encodeToFile
+
+
+ /**
+ * Convenience method for decoding data to a file.
+ * <p/>
+ * <p>As of v 2.3, if there is a error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned false, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param dataToDecode Base64-encoded data as a string
+ * @param filename Filename for saving decoded data
+ * @throws java.io.IOException if there is an error
+ * @since 2.1
+ */
+ public static void decodeToFile(String dataToDecode, String filename)
+ throws java.io.IOException
+ {
+
+ Base64.OutputStream bos = null;
+ try
+ {
+ bos = new Base64.OutputStream(
+ new java.io.FileOutputStream(filename), Base64.DECODE);
+ bos.write(dataToDecode.getBytes(PREFERRED_ENCODING));
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and throw to execute finally{} block
+ } // end catch: java.io.IOException
+ finally
+ {
+ try
+ { bos.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ } // end decodeToFile
+
+
+ /**
+ * Convenience method for reading a base64-encoded
+ * file and decoding it.
+ * <p/>
+ * <p>As of v 2.3, if there is a error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned false, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param filename Filename for reading encoded data
+ * @return decoded byte array
+ * @throws java.io.IOException if there is an error
+ * @since 2.1
+ */
+ public static byte[] decodeFromFile(String filename)
+ throws java.io.IOException
+ {
+
+ byte[] decodedData = null;
+ Base64.InputStream bis = null;
+ try
+ {
+ // Set up some useful variables
+ java.io.File file = new java.io.File(filename);
+ byte[] buffer = null;
+ int length = 0;
+ int numBytes = 0;
+
+ // Check for size of file
+ if (file.length() > Integer.MAX_VALUE)
+ {
+ throw new java.io.IOException("File is too big for this convenience method (" + file.length() + " bytes).");
+ } // end if: file too big for int index
+ buffer = new byte[(int) file.length()];
+
+ // Open a stream
+ bis = new Base64.InputStream(
+ new java.io.BufferedInputStream(
+ new java.io.FileInputStream(file)), Base64.DECODE);
+
+ // Read until done
+ while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
+ {
+ length += numBytes;
+ } // end while
+
+ // Save in a variable to return
+ decodedData = new byte[length];
+ System.arraycopy(buffer, 0, decodedData, 0, length);
+
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and release to execute finally{}
+ } // end catch: java.io.IOException
+ finally
+ {
+ try
+ { bis.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ return decodedData;
+ } // end decodeFromFile
+
+
+ /**
+ * Convenience method for reading a binary file
+ * and base64-encoding it.
+ * <p/>
+ * <p>As of v 2.3, if there is a error,
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+ * In earlier versions, it just returned false, but
+ * in retrospect that's a pretty poor way to handle it.</p>
+ *
+ * @param filename Filename for reading binary data
+ * @return base64-encoded string
+ * @throws java.io.IOException if there is an error
+ * @since 2.1
+ */
+ public static String encodeFromFile(String filename)
+ throws java.io.IOException
+ {
+
+ String encodedData = null;
+ Base64.InputStream bis = null;
+ try
+ {
+ // Set up some useful variables
+ java.io.File file = new java.io.File(filename);
+ byte[] buffer = new byte[Math.max((int) (file.length() * 1.4 + 1), 40)]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5)
+ int length = 0;
+ int numBytes = 0;
+
+ // Open a stream
+ bis = new Base64.InputStream(
+ new java.io.BufferedInputStream(
+ new java.io.FileInputStream(file)), Base64.ENCODE);
+
+ // Read until done
+ while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
+ {
+ length += numBytes;
+ } // end while
+
+ // Save in a variable to return
+ encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING);
+
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and release to execute finally{}
+ } // end catch: java.io.IOException
+ finally
+ {
+ try
+ { bis.close(); }
+ catch (Exception e)
+ {}
+ } // end finally
+
+ return encodedData;
+ } // end encodeFromFile
+
+ /**
+ * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
+ *
+ * @param infile Input file
+ * @param outfile Output file
+ * @throws java.io.IOException if there is an error
+ * @since 2.2
+ */
+ public static void encodeFileToFile(String infile, String outfile)
+ throws java.io.IOException
+ {
+
+ String encoded = Base64.encodeFromFile(infile);
+ java.io.OutputStream out = null;
+ try
+ {
+ out = new java.io.BufferedOutputStream(
+ new java.io.FileOutputStream(outfile));
+ out.write(encoded.getBytes("US-ASCII")); // Strict, 7-bit output.
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and release to execute finally{}
+ } // end catch
+ finally
+ {
+ try
+ { out.close(); }
+ catch (Exception ex)
+ {}
+ } // end finally
+ } // end encodeFileToFile
+
+
+ /**
+ * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
+ *
+ * @param infile Input file
+ * @param outfile Output file
+ * @throws java.io.IOException if there is an error
+ * @since 2.2
+ */
+ public static void decodeFileToFile(String infile, String outfile)
+ throws java.io.IOException
+ {
+
+ byte[] decoded = Base64.decodeFromFile(infile);
+ java.io.OutputStream out = null;
+ try
+ {
+ out = new java.io.BufferedOutputStream(
+ new java.io.FileOutputStream(outfile));
+ out.write(decoded);
+ } // end try
+ catch (java.io.IOException e)
+ {
+ throw e; // Catch and release to execute finally{}
+ } // end catch
+ finally
+ {
+ try
+ { out.close(); }
+ catch (Exception ex)
+ {}
+ } // end finally
+ } // end decodeFileToFile
+
+
+ /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
+
+
+ /**
+ * A {@link Base64.InputStream} will read data from another
+ * <tt>java.io.InputStream</tt>, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class InputStream extends java.io.FilterInputStream
+ {
+
+ private boolean encode; // Encoding or decoding
+ private int position; // Current position in the buffer
+ private byte[] buffer; // Small buffer holding converted data
+ private int bufferLength; // Length of buffer (3 or 4)
+ private int numSigBytes; // Number of meaningful bytes in the buffer
+ private int lineLength;
+ private boolean breakLines; // Break lines at less than 80 characters
+ private int options; // Record options used to create the stream.
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in DECODE mode.
+ *
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.
+ * @since 1.3
+ */
+ public InputStream(java.io.InputStream in)
+ {
+ this(in, DECODE);
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in
+ * either ENCODE or DECODE mode.
+ * <p/>
+ * Valid options:<pre>
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DO_BREAK_LINES: break lines at 76 characters
+ * (only meaningful when encoding)</i>
+ * </pre>
+ * <p/>
+ * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
+ *
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.
+ * @param options Specified options
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.0
+ */
+ public InputStream(java.io.InputStream in, int options)
+ {
+
+ super(in);
+ this.options = options; // Record for later
+ this.breakLines = (options & DO_BREAK_LINES) > 0;
+ this.encode = (options & ENCODE) > 0;
+ this.bufferLength = encode ? 4 : 3;
+ this.buffer = new byte[bufferLength];
+ this.position = -1;
+ this.lineLength = 0;
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+ /**
+ * Reads enough of the input stream to convert
+ * to/from Base64 and returns the next byte.
+ *
+ * @return next byte
+ * @since 1.3
+ */
+ @Override
+ public int read() throws java.io.IOException
+ {
+
+ // Do we need to get data?
+ if (position < 0)
+ {
+ if (encode)
+ {
+ byte[] b3 = new byte[3];
+ int numBinaryBytes = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ int b = in.read();
+
+ // If end of stream, b is -1.
+ if (b >= 0)
+ {
+ b3[i] = (byte) b;
+ numBinaryBytes++;
+ }
+ else
+ {
+ break; // out of for loop
+ } // end else: end of stream
+
+ } // end for: each needed input byte
+
+ if (numBinaryBytes > 0)
+ {
+ encode3to4(b3, 0, numBinaryBytes, buffer, 0, options);
+ position = 0;
+ numSigBytes = 4;
+ } // end if: got data
+ else
+ {
+ return -1; // Must be end of stream
+ } // end else
+ } // end if: encoding
+
+ // Else decoding
+ else
+ {
+ byte[] b4 = new byte[4];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ {
+ // Read four "meaningful" bytes:
+ int b = 0;
+ do
+ { b = in.read(); }
+ while (b >= 0 && decodabet[b & 0x7f] <= WHITE_SPACE_ENC);
+
+ if (b < 0)
+ {
+ break; // Reads a -1 if end of stream
+ } // end if: end of stream
+
+ b4[i] = (byte) b;
+ } // end for: each needed input byte
+
+ if (i == 4)
+ {
+ numSigBytes = decode4to3(b4, 0, buffer, 0, options);
+ position = 0;
+ } // end if: got four characters
+ else if (i == 0)
+ {
+ return -1;
+ } // end else if: also padded correctly
+ else
+ {
+ // Must have broken out from above.
+ throw new java.io.IOException("Improperly padded Base64 input.");
+ } // end
+
+ } // end else: decode
+ } // end else: get data
+
+ // Got data?
+ if (position >= 0)
+ {
+ // End of relevant data?
+ if ( /*!encode &&*/ position >= numSigBytes)
+ {
+ return -1;
+ } // end if: got data
+
+ if (encode && breakLines && lineLength >= MAX_LINE_LENGTH)
+ {
+ lineLength = 0;
+ return '\n';
+ } // end if
+ else
+ {
+ lineLength++; // This isn't important when decoding
+ // but throwing an extra "if" seems
+ // just as wasteful.
+
+ int b = buffer[position++];
+
+ if (position >= bufferLength)
+ {
+ position = -1;
+ } // end if: end
+
+ return b & 0xFF; // This is how you "cast" a byte that's
+ // intended to be unsigned.
+ } // end else
+ } // end if: position >= 0
+
+ // Else error
+ else
+ {
+ throw new java.io.IOException("Error in Base64 code reading stream.");
+ } // end else
+ } // end read
+
+
+ /**
+ * Calls {@link #read()} repeatedly until the end of stream
+ * is reached or <var>len</var> bytes are read.
+ * Returns number of bytes read into array or -1 if
+ * end of stream is encountered.
+ *
+ * @param dest array to hold values
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @return bytes read into array or -1 if end of stream is encountered.
+ * @since 1.3
+ */
+ @Override
+ public int read(byte[] dest, int off, int len)
+ throws java.io.IOException
+ {
+ int i;
+ int b;
+ for (i = 0; i < len; i++)
+ {
+ b = read();
+
+ if (b >= 0)
+ {
+ dest[off + i] = (byte) b;
+ }
+ else if (i == 0)
+ {
+ return -1;
+ }
+ else
+ {
+ break; // Out of 'for' loop
+ } // Out of 'for' loop
+ } // end for: each byte read
+ return i;
+ } // end read
+
+ } // end inner class InputStream
+
+
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
+
+
+ /**
+ * A {@link Base64.OutputStream} will write data to another
+ * <tt>java.io.OutputStream</tt>, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class OutputStream extends java.io.FilterOutputStream
+ {
+
+ private boolean encode;
+ private int position;
+ private byte[] buffer;
+ private int bufferLength;
+ private int lineLength;
+ private boolean breakLines;
+ private byte[] b4; // Scratch used in a few places
+ private boolean suspendEncoding;
+ private int options; // Record for later
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+ *
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+ * @since 1.3
+ */
+ public OutputStream(java.io.OutputStream out)
+ {
+ this(out, ENCODE);
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in
+ * either ENCODE or DECODE mode.
+ * <p/>
+ * Valid options:<pre>
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DO_BREAK_LINES: don't break lines at 76 characters
+ * (only meaningful when encoding)</i>
+ * </pre>
+ * <p/>
+ * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
+ *
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+ * @param options Specified options.
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DO_BREAK_LINES
+ * @since 1.3
+ */
+ public OutputStream(java.io.OutputStream out, int options)
+ {
+ super(out);
+ this.breakLines = (options & DO_BREAK_LINES) != 0;
+ this.encode = (options & ENCODE) != 0;
+ this.bufferLength = encode ? 3 : 4;
+ this.buffer = new byte[bufferLength];
+ this.position = 0;
+ this.lineLength = 0;
+ this.suspendEncoding = false;
+ this.b4 = new byte[4];
+ this.options = options;
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+
+ /**
+ * Writes the byte to the output stream after
+ * converting to/from Base64 notation.
+ * When encoding, bytes are buffered three
+ * at a time before the output stream actually
+ * gets a write() call.
+ * When decoding, bytes are buffered four
+ * at a time.
+ *
+ * @param theByte the byte to write
+ * @since 1.3
+ */
+ @Override
+ public void write(int theByte)
+ throws java.io.IOException
+ {
+ // Encoding suspended?
+ if (suspendEncoding)
+ {
+ this.out.write(theByte);
+ return;
+ } // end if: supsended
+
+ // Encode?
+ if (encode)
+ {
+ buffer[position++] = (byte) theByte;
+ if (position >= bufferLength)
+ { // Enough to encode.
+
+ this.out.write(encode3to4(b4, buffer, bufferLength, options));
+
+ lineLength += 4;
+ if (breakLines && lineLength >= MAX_LINE_LENGTH)
+ {
+ this.out.write(NEW_LINE);
+ lineLength = 0;
+ } // end if: end of line
+
+ position = 0;
+ } // end if: enough to output
+ } // end if: encoding
+
+ // Else, Decoding
+ else
+ {
+ // Meaningful Base64 character?
+ if (decodabet[theByte & 0x7f] > WHITE_SPACE_ENC)
+ {
+ buffer[position++] = (byte) theByte;
+ if (position >= bufferLength)
+ { // Enough to output.
+
+ int len = Base64.decode4to3(buffer, 0, b4, 0, options);
+ out.write(b4, 0, len);
+ position = 0;
+ } // end if: enough to output
+ } // end if: meaningful base64 character
+ else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC)
+ {
+ throw new java.io.IOException("Invalid character in Base64 data.");
+ } // end else: not white space either
+ } // end else: decoding
+ } // end write
+
+
+ /**
+ * Calls {@link #write(int)} repeatedly until <var>len</var>
+ * bytes are written.
+ *
+ * @param theBytes array from which to read bytes
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @since 1.3
+ */
+ @Override
+ public void write(byte[] theBytes, int off, int len)
+ throws java.io.IOException
+ {
+ // Encoding suspended?
+ if (suspendEncoding)
+ {
+ this.out.write(theBytes, off, len);
+ return;
+ } // end if: supsended
+
+ for (int i = 0; i < len; i++)
+ {
+ write(theBytes[off + i]);
+ } // end for: each byte written
+
+ } // end write
+
+
+ /**
+ * Method added by PHIL. [Thanks, PHIL. -Rob]
+ * This pads the buffer without closing the stream.
+ *
+ * @throws java.io.IOException if there's an error.
+ */
+ public void flushBase64() throws java.io.IOException
+ {
+ if (position > 0)
+ {
+ if (encode)
+ {
+ out.write(encode3to4(b4, buffer, position, options));
+ position = 0;
+ } // end if: encoding
+ else
+ {
+ throw new java.io.IOException("Base64 input not properly padded.");
+ } // end else: decoding
+ } // end if: buffer partially full
+
+ } // end flush
+
+
+ /**
+ * Flushes and closes (I think, in the superclass) the stream.
+ *
+ * @since 1.3
+ */
+ @Override
+ public void close() throws java.io.IOException
+ {
+ // 1. Ensure that pending characters are written
+ flushBase64();
+
+ // 2. Actually close the stream
+ // Base class both flushes and closes.
+ super.close();
+
+ buffer = null;
+ out = null;
+ } // end close
+
+
+ /**
+ * Suspends encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base64-encoded data in a stream.
+ *
+ * @throws java.io.IOException if there's an error flushing
+ * @since 1.5.1
+ */
+ public void suspendEncoding() throws java.io.IOException
+ {
+ flushBase64();
+ this.suspendEncoding = true;
+ } // end suspendEncoding
+
+
+ /**
+ * Resumes encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base64-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void resumeEncoding()
+ {
+ this.suspendEncoding = false;
+ } // end resumeEncoding
+
+
+ } // end inner class OutputStream
+
+
+} // end class Base64
diff --git a/model/api/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java b/model/api/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java
new file mode 100755
index 0000000..a9fec22
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java
@@ -0,0 +1,58 @@
+package org.keycloak.models.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+/**
+ * <p>
+ * Password that uses SHA to encode passwords. You can always change the SHA strength by specifying a valid
+ * integer when creating a new instance.
+ * </p>
+ * <p>Passwords are returned with a Base64 encoding.</p>
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Silva</a>
+ *
+ */
+public class SHAPasswordEncoder {
+
+ private int strength;
+
+ public SHAPasswordEncoder(int strength) {
+ this.strength = strength;
+ }
+
+ public String encode(String rawPassword) {
+ MessageDigest messageDigest = getMessageDigest();
+
+ String encodedPassword = null;
+
+ try {
+ byte[] digest = messageDigest.digest(rawPassword.getBytes("UTF-8"));
+ encodedPassword = Base64.encodeBytes(digest);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("Credential could not be encoded");
+ }
+
+ return encodedPassword;
+ }
+
+ public boolean verify(String rawPassword, String encodedPassword) {
+ return encode(rawPassword).equals(encodedPassword);
+ }
+
+ protected final MessageDigest getMessageDigest() throws IllegalArgumentException {
+ String algorithm = "SHA-" + this.strength;
+
+ try {
+ return MessageDigest.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("invalid credential encoding algorithm");
+ }
+ }
+
+ public int getStrength() {
+ return this.strength;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java b/model/api/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java
new file mode 100755
index 0000000..d27718b
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java
@@ -0,0 +1,216 @@
+package org.keycloak.models.utils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * TOTP: Time-based One-time Password Algorithm Based on http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
+ *
+ * @author anil saldhana
+ * @since Sep 20, 2010
+ */
+public class TimeBasedOTP {
+
+ public static final String HMAC_SHA1 = "HmacSHA1";
+ public static final String HMAC_SHA256 = "HmacSHA256";
+ public static final String HMAC_SHA512 = "HmacSHA512";
+
+ public static final String DEFAULT_ALGORITHM = HMAC_SHA1;
+ public static final int DEFAULT_NUMBER_DIGITS = 6;
+ public static final int DEFAULT_INTERVAL_SECONDS = 30;
+ public static final int DEFAULT_DELAY_WINDOW = 1;
+
+ // 0 1 2 3 4 5 6 7 8
+ private static final int[] DIGITS_POWER = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
+
+ private Clock clock;
+ private final String algorithm;
+ private final int numberDigits;
+ private final int delayWindow;
+
+ public TimeBasedOTP() {
+ this(DEFAULT_ALGORITHM, DEFAULT_NUMBER_DIGITS, DEFAULT_INTERVAL_SECONDS, DEFAULT_DELAY_WINDOW);
+ }
+
+ /**
+ * @param algorithm the encryption algorithm
+ * @param numberDigits the number of digits for tokens
+ * @param timeIntervalInSeconds the number of seconds a token is valid
+ * @param delayWindow the number of previous intervals that should be used to validate tokens.
+ */
+ public TimeBasedOTP(String algorithm, int numberDigits, int timeIntervalInSeconds, int delayWindow) {
+ this.algorithm = algorithm;
+ this.numberDigits = numberDigits;
+ this.clock = new Clock(timeIntervalInSeconds);
+ this.delayWindow = delayWindow;
+ }
+
+ /**
+ * <p>Generates a token.</p>
+ *
+ * @param secretKey the secret key to derive the token from.
+ */
+ public String generate(String secretKey) {
+ long T = this.clock.getCurrentInterval();
+
+ String steps = Long.toHexString(T).toUpperCase();
+
+ // Just get a 16 digit string
+ while (steps.length() < 16)
+ steps = "0" + steps;
+
+ return generateTOTP(secretKey, steps, this.numberDigits, this.algorithm);
+ }
+
+ /**
+ * This method generates an TOTP value for the given set of parameters.
+ *
+ * @param key the shared secret, HEX encoded
+ * @param time a value that reflects a time
+ * @param returnDigits number of digits to return
+ * @param crypto the crypto function to use
+ * @return A numeric String in base 10 that includes {@link truncationDigits} digits
+ * @throws java.security.GeneralSecurityException
+ *
+ */
+ public String generateTOTP(String key, String time, int returnDigits, String crypto) {
+ String result = null;
+ byte[] hash;
+
+ // Using the counter
+ // First 8 bytes are for the movingFactor
+ // Complaint with base RFC 4226 (HOTP)
+ while (time.length() < 16)
+ time = "0" + time;
+
+ // Get the HEX in a Byte[]
+ byte[] msg = hexStr2Bytes(time);
+
+ // Adding one byte to get the right conversion
+ // byte[] k = hexStr2Bytes(key);
+ byte[] k = key.getBytes();
+
+ hash = hmac_sha1(crypto, k, msg);
+
+ // put selected bytes into result int
+ int offset = hash[hash.length - 1] & 0xf;
+
+ int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) | ((hash[offset + 2] & 0xff) << 8)
+ | (hash[offset + 3] & 0xff);
+
+ int otp = binary % DIGITS_POWER[returnDigits];
+
+ result = Integer.toString(otp);
+
+ while (result.length() < returnDigits) {
+ result = "0" + result;
+ }
+ return result;
+ }
+
+ /**
+ * <p>Validates a token using a secret key.</p>
+ *
+ * @param token OTP string to validate
+ * @param secret Shared secret
+ * @return
+ */
+ public boolean validate(String token, byte[] secret) {
+ long currentInterval = this.clock.getCurrentInterval();
+
+ for (int i = this.delayWindow; i >= 0; --i) {
+ String steps = Long.toHexString(currentInterval - i).toUpperCase();
+
+ // Just get a 16 digit string
+ while (steps.length() < 16)
+ steps = "0" + steps;
+
+ String candidate = generateTOTP(new String(secret), steps, this.numberDigits, this.algorithm);
+
+ if (candidate.equals(token)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void setCalendar(Calendar calendar) {
+ this.clock.setCalendar(calendar);
+ }
+
+ /**
+ * This method uses the JCE to provide the crypto algorithm. HMAC computes a Hashed Message Authentication Code with the
+ * crypto hash algorithm as a parameter.
+ *
+ * @param crypto the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)
+ * @param keyBytes the bytes to use for the HMAC key
+ * @param text the message or text to be authenticated.
+ * @throws java.security.NoSuchAlgorithmException
+ *
+ * @throws java.security.InvalidKeyException
+ *
+ */
+ private byte[] hmac_sha1(String crypto, byte[] keyBytes, byte[] text) {
+ byte[] value;
+
+ try {
+ Mac hmac = Mac.getInstance(crypto);
+ SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
+
+ hmac.init(macKey);
+
+ value = hmac.doFinal(text);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return value;
+ }
+
+ /**
+ * This method converts HEX string to Byte[]
+ *
+ * @param hex the HEX string
+ * @return A byte array
+ */
+ private byte[] hexStr2Bytes(String hex) {
+ // Adding one byte to get the right conversion
+ // values starting with "0" can be converted
+ byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
+
+ // Copy all the REAL bytes, not the "first"
+ byte[] ret = new byte[bArray.length - 1];
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = bArray[i + 1];
+ return ret;
+ }
+
+ private class Clock {
+
+ private final int interval;
+ private Calendar calendar;
+
+ public Clock(int interval) {
+ this.interval = interval;
+ }
+
+ public long getCurrentInterval() {
+ Calendar currentCalendar = this.calendar;
+
+ if (currentCalendar == null) {
+ currentCalendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
+ }
+
+ return (currentCalendar.getTimeInMillis() / 1000) / this.interval;
+ }
+
+ public void setCalendar(Calendar calendar) {
+ this.calendar = calendar;
+ }
+ }
+}
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
new file mode 100755
index 0000000..00ed540
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -0,0 +1,332 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.ApplicationEntity;
+import org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity;
+import org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity;
+import org.keycloak.models.jpa.entities.RoleEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ApplicationAdapter implements ApplicationModel {
+
+ protected EntityManager em;
+ protected ApplicationEntity application;
+
+ public ApplicationAdapter(EntityManager em, ApplicationEntity application) {
+ this.em = em;
+ this.application = application;
+ }
+
+ @Override
+ public void updateApplication() {
+ em.flush();
+ }
+
+ @Override
+ public UserModel getApplicationUser() {
+ return new UserAdapter(application.getApplicationUser());
+ }
+
+ @Override
+ public String getId() {
+ return application.getId();
+ }
+
+ @Override
+ public String getName() {
+ return application.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ application.setName(name);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return application.isEnabled();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ application.setEnabled(enabled);
+ }
+
+ @Override
+ public boolean isSurrogateAuthRequired() {
+ return application.isSurrogateAuthRequired();
+ }
+
+ @Override
+ public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+ application.setSurrogateAuthRequired(surrogateAuthRequired);
+ }
+
+ @Override
+ public String getManagementUrl() {
+ return application.getManagementUrl();
+ }
+
+ @Override
+ public void setManagementUrl(String url) {
+ application.setManagementUrl(url);
+ }
+
+ @Override
+ public String getBaseUrl() {
+ return null;
+ }
+
+ @Override
+ public void setBaseUrl(String url) {
+ }
+
+ @Override
+ public RoleModel getRole(String name) {
+ Collection<RoleEntity> roles = application.getRoles();
+ if (roles == null) return null;
+ for (RoleEntity role : roles) {
+ if (role.getName().equals(name)) {
+ return new RoleAdapter(role);
+ }
+ }
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public RoleModel addRole(String name) {
+ RoleModel role = getRole(name);
+ if (role != null) return role;
+ RoleEntity entity = new RoleEntity();
+ entity.setName(name);
+ em.persist(entity);
+ application.getRoles().add(entity);
+ em.flush();
+ return new RoleAdapter(entity);
+ }
+
+ @Override
+ public List<RoleModel> getRoles() {
+ ArrayList<RoleModel> list = new ArrayList<RoleModel>();
+ Collection<RoleEntity> roles = application.getRoles();
+ if (roles == null) return list;
+ for (RoleEntity entity : roles) {
+ list.add(new RoleAdapter(entity));
+ }
+ return list;
+ }
+
+ @Override
+ public RoleModel getRoleById(String id) {
+ RoleEntity entity = em.find(RoleEntity.class, id);
+ if (entity == null) return null;
+ return new RoleAdapter(entity);
+ }
+
+ @Override
+ public boolean hasRole(UserModel user, RoleModel role) {
+ TypedQuery<ApplicationUserRoleMappingEntity> query = getApplicationUserRoleMappingEntityTypedQuery((UserAdapter) user, (RoleAdapter) role);
+ return query.getResultList().size() > 0;
+ }
+
+ protected TypedQuery<ApplicationUserRoleMappingEntity> getApplicationUserRoleMappingEntityTypedQuery(UserAdapter user, RoleAdapter role) {
+ TypedQuery<ApplicationUserRoleMappingEntity> query = em.createNamedQuery("userHasApplicationRole", ApplicationUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("role", ((RoleAdapter)role).getRole());
+ query.setParameter("application", application);
+ return query;
+ }
+
+ @Override
+ public void grantRole(UserModel user, RoleModel role) {
+ if (hasRole(user, role)) return;
+ ApplicationUserRoleMappingEntity entity = new ApplicationUserRoleMappingEntity();
+ entity.setApplication(application);
+ entity.setUser(((UserAdapter) user).getUser());
+ entity.setRole(((RoleAdapter)role).getRole());
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public List<RoleModel> getRoleMappings(UserModel user) {
+ TypedQuery<ApplicationUserRoleMappingEntity> query = em.createNamedQuery("userApplicationMappings", ApplicationUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("application", application);
+ List<ApplicationUserRoleMappingEntity> entities = query.getResultList();
+ List<RoleModel> roles = new ArrayList<RoleModel>();
+ for (ApplicationUserRoleMappingEntity entity : entities) {
+ roles.add(new RoleAdapter(entity.getRole()));
+ }
+ return roles;
+ }
+
+ @Override
+ public Set<String> getRoleMappingValues(UserModel user) {
+ TypedQuery<ApplicationUserRoleMappingEntity> query = em.createNamedQuery("userApplicationMappings", ApplicationUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("application", application);
+ List<ApplicationUserRoleMappingEntity> entities = query.getResultList();
+ Set<String> roles = new HashSet<String>();
+ for (ApplicationUserRoleMappingEntity entity : entities) {
+ roles.add(entity.getRole().getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public void deleteRoleMapping(UserModel user, RoleModel role) {
+ TypedQuery<ApplicationUserRoleMappingEntity> query = getApplicationUserRoleMappingEntityTypedQuery((UserAdapter) user, (RoleAdapter) role);
+ List<ApplicationUserRoleMappingEntity> results = query.getResultList();
+ if (results.size() == 0) return;
+ for (ApplicationUserRoleMappingEntity entity : results) {
+ em.remove(entity);
+ }
+ }
+
+ @Override
+ public boolean hasRole(UserModel user, String roleName) {
+ RoleModel role = getRole(roleName);
+ if (role == null) return false;
+ return hasRole(user, role);
+ }
+
+ @Override
+ public void addScopeMapping(UserModel agent, String roleName) {
+ RoleModel role = getRole(roleName);
+ if (role == null) throw new RuntimeException("role does not exist");
+ addScopeMapping(agent, role);
+ }
+
+ @Override
+ public Set<String> getScopeMappingValues(UserModel agent) {
+ TypedQuery<ApplicationScopeMappingEntity> query = em.createNamedQuery("userApplicationScopeMappings", ApplicationScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)agent).getUser());
+ query.setParameter("application", application);
+ List<ApplicationScopeMappingEntity> entities = query.getResultList();
+ Set<String> roles = new HashSet<String>();
+ for (ApplicationScopeMappingEntity entity : entities) {
+ roles.add(entity.getRole().getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public List<RoleModel> getScopeMappings(UserModel agent) {
+ TypedQuery<ApplicationScopeMappingEntity> query = em.createNamedQuery("userApplicationScopeMappings", ApplicationScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)agent).getUser());
+ query.setParameter("application", application);
+ List<ApplicationScopeMappingEntity> entities = query.getResultList();
+ List<RoleModel> roles = new ArrayList<RoleModel>();
+ for (ApplicationScopeMappingEntity entity : entities) {
+ roles.add(new RoleAdapter(entity.getRole()));
+ }
+ return roles;
+ }
+
+ @Override
+ public void addScopeMapping(UserModel agent, RoleModel role) {
+ if (hasScope(agent, role)) return;
+ ApplicationScopeMappingEntity entity = new ApplicationScopeMappingEntity();
+ entity.setApplication(application);
+ entity.setUser(((UserAdapter) agent).getUser());
+ entity.setRole(((RoleAdapter)role).getRole());
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public void deleteScopeMapping(UserModel user, RoleModel role) {
+ TypedQuery<ApplicationScopeMappingEntity> query = getApplicationScopeMappingQuery((UserAdapter) user, (RoleAdapter) role);
+ List<ApplicationScopeMappingEntity> results = query.getResultList();
+ if (results.size() == 0) return;
+ for (ApplicationScopeMappingEntity entity : results) {
+ em.remove(entity);
+ }
+ }
+
+ public boolean hasScope(UserModel user, RoleModel role) {
+ TypedQuery<ApplicationScopeMappingEntity> query = getApplicationScopeMappingQuery((UserAdapter) user, (RoleAdapter) role);
+ return query.getResultList().size() > 0;
+ }
+
+
+ protected TypedQuery<ApplicationScopeMappingEntity> getApplicationScopeMappingQuery(UserAdapter user, RoleAdapter role) {
+ TypedQuery<ApplicationScopeMappingEntity> query = em.createNamedQuery("userHasApplicationScope", ApplicationScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("role", ((RoleAdapter)role).getRole());
+ query.setParameter("application", application);
+ return query;
+ }
+
+ @Override
+ public List<String> getDefaultRoles() {
+ Collection<RoleEntity> entities = application.getDefaultRoles();
+ List<String> roles = new ArrayList<String>();
+ if (entities == null) return roles;
+ for (RoleEntity entity : entities) {
+ roles.add(entity.getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public void addDefaultRole(String name) {
+ RoleModel role = getRole(name);
+ if (role == null) {
+ role = addRole(name);
+ }
+ Collection<RoleEntity> entities = application.getDefaultRoles();
+ for (RoleEntity entity : entities) {
+ if (entity.getId().equals(role.getId())) {
+ return;
+ }
+ }
+ entities.add(((RoleAdapter) role).getRole());
+ em.flush();
+ }
+
+ public static boolean contains(String str, String[] array) {
+ for (String s : array) {
+ if (str.equals(s)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void updateDefaultRoles(String[] defaultRoles) {
+ Collection<RoleEntity> entities = application.getDefaultRoles();
+ Set<String> already = new HashSet<String>();
+ List<RoleEntity> remove = new ArrayList<RoleEntity>();
+ for (RoleEntity rel : entities) {
+ if (!contains(rel.getName(), defaultRoles)) {
+ remove.add(rel);
+ } else {
+ already.add(rel.getName());
+ }
+ }
+ for (RoleEntity entity : remove) {
+ entities.remove(entity);
+ }
+ em.flush();
+ for (String roleName : defaultRoles) {
+ if (!already.contains(roleName)) {
+ addDefaultRole(roleName);
+ }
+ }
+ em.flush();
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationScopeMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationScopeMappingEntity.java
new file mode 100755
index 0000000..557c65d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationScopeMappingEntity.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="userHasApplicationScope", query="select m from ApplicationScopeMappingEntity m where m.user = :user and m.role = :role and m.application = :application"),
+ @NamedQuery(name="userApplicationScopeMappings", query="select m from ApplicationScopeMappingEntity m where m.user = :user and m.application = :application")
+})
+@Entity
+public class ApplicationScopeMappingEntity extends UserRoleMappingEntity {
+
+ @ManyToOne
+ protected ApplicationEntity application;
+
+ public ApplicationEntity getApplication() {
+ return application;
+ }
+
+ public void setApplication(ApplicationEntity application) {
+ this.application = application;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationUserRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationUserRoleMappingEntity.java
new file mode 100755
index 0000000..2b2461d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationUserRoleMappingEntity.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="userHasApplicationRole", query="select m from ApplicationUserRoleMappingEntity m where m.user = :user and m.role = :role and m.application = :application"),
+ @NamedQuery(name="userApplicationMappings", query="select m from ApplicationUserRoleMappingEntity m where m.user = :user and m.application = :application")
+})
+@Entity
+public class ApplicationUserRoleMappingEntity extends UserRoleMappingEntity {
+
+ @ManyToOne
+ protected ApplicationEntity application;
+
+ public ApplicationEntity getApplication() {
+ return application;
+ }
+
+ public void setApplication(ApplicationEntity application) {
+ this.application = application;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java
new file mode 100755
index 0000000..4b13fd6
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java
@@ -0,0 +1,69 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="credentialByUserAndType", query="select cred from CredentialEntity cred where cred.user = :user and cred.type = :type")
+})
+@Entity
+public class CredentialEntity {
+ @Id
+ @GeneratedValue
+ protected String id;
+
+ protected String type;
+ protected String value;
+ protected String device;
+
+ @ManyToOne
+ protected UserEntity user;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getDevice() {
+ return device;
+ }
+
+ public void setDevice(String device) {
+ this.device = device;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public void setUser(UserEntity user) {
+ this.user = user;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java
new file mode 100755
index 0000000..28e158d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java
@@ -0,0 +1,62 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToOne;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="findOAuthClientByUser", query="select o from OAuthClientEntity o where o.agent.loginName=:name and o.realm = :realm"),
+ @NamedQuery(name="findOAuthClientByRealm", query="select o from OAuthClientEntity o where o.realm = :realm")
+
+})
+@Entity
+public class OAuthClientEntity {
+ @Id
+ @GeneratedValue
+ private String id;
+
+ private String name;
+
+ @OneToOne(fetch = FetchType.EAGER)
+ private UserEntity agent;
+
+ @ManyToOne
+ protected RealmEntity realm;
+
+ public String getId() {
+ return id;
+ }
+
+ public UserEntity getAgent() {
+ return agent;
+ }
+
+ public void setAgent(UserEntity agent) {
+ this.agent = agent;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 4a8ea65..d82c68e 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -1,43 +1,272 @@
package org.keycloak.models.jpa.entities;
-import javax.persistence.*;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.OneToMany;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
+@Entity
public class RealmEntity {
@Id
protected String id;
- protected String realmName;
+ protected String name;
protected boolean enabled;
protected boolean sslNotRequired;
protected boolean cookieLoginAllowed;
protected boolean registrationAllowed;
+ protected boolean verifyEmail;
+ protected boolean resetPasswordAllowed;
+ protected boolean social;
+ protected boolean automaticRegistrationAfterSocialLogin;
+
protected int tokenLifespan;
protected int accessCodeLifespan;
+ protected int accessCodeLifespanUserAction;
+
@Column(length = 2048)
protected String publicKeyPem;
@Column(length = 2048)
protected String privateKeyPem;
- protected String[] defaultRoles;
- @Lob
- protected HashMap<String, String> smtpConfig;
- @Lob
- protected HashMap<String, String> socialConfig;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
- Collection<RequiredCredentailEntity> requiredCredentials;
+ @JoinTable(name="USER_REQUIRED_CREDENTIALS")
+ Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
+
+ @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
+ @JoinTable(name="APPLICATION_REQUIRED_CREDENTIALS")
+ Collection<RequiredCredentialEntity> requiredApplicationCredentials = new ArrayList<RequiredCredentialEntity>();
+
+ @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
+ @JoinTable(name="OAUTH_CLIENT_REQUIRED_CREDENTIALS")
+ Collection<RequiredCredentialEntity> requiredOAuthClientCredentials = new ArrayList<RequiredCredentialEntity>();
+
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
- Collection<ResourceEntity> resources;
+ Collection<ApplicationEntity> applications = new ArrayList<ApplicationEntity>();
+
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
- Collection<RoleEntity> roles;
+ @JoinTable(name="REALM_ROLES")
+ Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
+
+ @ElementCollection
+ @MapKeyColumn(name="name")
+ @Column(name="value")
+ @CollectionTable
+ protected Map<String, String> smtpConfig = new HashMap<String, String>();
+
+ @ElementCollection
+ @MapKeyColumn(name="name")
+ @Column(name="value")
+ @CollectionTable
+ protected Map<String, String> socialConfig = new HashMap<String, String>();
+
+ @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
+ @JoinTable(name="REALM_DEFAULT_ROLES")
+ Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isSslNotRequired() {
+ return sslNotRequired;
+ }
+
+ public void setSslNotRequired(boolean sslNotRequired) {
+ this.sslNotRequired = sslNotRequired;
+ }
+
+ public boolean isCookieLoginAllowed() {
+ return cookieLoginAllowed;
+ }
+
+ public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
+ this.cookieLoginAllowed = cookieLoginAllowed;
+ }
+
+ public boolean isRegistrationAllowed() {
+ return registrationAllowed;
+ }
+
+ public void setRegistrationAllowed(boolean registrationAllowed) {
+ this.registrationAllowed = registrationAllowed;
+ }
+
+ public boolean isVerifyEmail() {
+ return verifyEmail;
+ }
+
+ public void setVerifyEmail(boolean verifyEmail) {
+ this.verifyEmail = verifyEmail;
+ }
+
+ public boolean isResetPasswordAllowed() {
+ return resetPasswordAllowed;
+ }
+
+ public void setResetPasswordAllowed(boolean resetPasswordAllowed) {
+ this.resetPasswordAllowed = resetPasswordAllowed;
+ }
+
+ public boolean isSocial() {
+ return social;
+ }
+
+ public void setSocial(boolean social) {
+ this.social = social;
+ }
+
+ public boolean isAutomaticRegistrationAfterSocialLogin() {
+ return automaticRegistrationAfterSocialLogin;
+ }
+
+ public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin) {
+ this.automaticRegistrationAfterSocialLogin = automaticRegistrationAfterSocialLogin;
+ }
+
+ public int getTokenLifespan() {
+ return tokenLifespan;
+ }
+
+ public void setTokenLifespan(int tokenLifespan) {
+ this.tokenLifespan = tokenLifespan;
+ }
+
+ public int getAccessCodeLifespan() {
+ return accessCodeLifespan;
+ }
+
+ public void setAccessCodeLifespan(int accessCodeLifespan) {
+ this.accessCodeLifespan = accessCodeLifespan;
+ }
+
+ public int getAccessCodeLifespanUserAction() {
+ return accessCodeLifespanUserAction;
+ }
+
+ public void setAccessCodeLifespanUserAction(int accessCodeLifespanUserAction) {
+ this.accessCodeLifespanUserAction = accessCodeLifespanUserAction;
+ }
+
+ public String getPublicKeyPem() {
+ return publicKeyPem;
+ }
+
+ public void setPublicKeyPem(String publicKeyPem) {
+ this.publicKeyPem = publicKeyPem;
+ }
+
+ public String getPrivateKeyPem() {
+ return privateKeyPem;
+ }
+
+ public void setPrivateKeyPem(String privateKeyPem) {
+ this.privateKeyPem = privateKeyPem;
+ }
+
+ public Collection<RequiredCredentialEntity> getRequiredCredentials() {
+ return requiredCredentials;
+ }
+
+ public void setRequiredCredentials(Collection<RequiredCredentialEntity> requiredCredentials) {
+ this.requiredCredentials = requiredCredentials;
+ }
+
+ public Collection<RequiredCredentialEntity> getRequiredApplicationCredentials() {
+ return requiredApplicationCredentials;
+ }
+
+ public void setRequiredApplicationCredentials(Collection<RequiredCredentialEntity> requiredApplicationCredentials) {
+ this.requiredApplicationCredentials = requiredApplicationCredentials;
+ }
+
+ public Collection<RequiredCredentialEntity> getRequiredOAuthClientCredentials() {
+ return requiredOAuthClientCredentials;
+ }
+
+ public void setRequiredOAuthClientCredentials(Collection<RequiredCredentialEntity> requiredOAuthClientCredentials) {
+ this.requiredOAuthClientCredentials = requiredOAuthClientCredentials;
+ }
+
+ public Collection<ApplicationEntity> getApplications() {
+ return applications;
+ }
+
+ public void setApplications(Collection<ApplicationEntity> applications) {
+ this.applications = applications;
+ }
+
+ public Collection<RoleEntity> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Collection<RoleEntity> roles) {
+ this.roles = roles;
+ }
+
+ public void addRole(RoleEntity role) {
+ if (roles == null) {
+ roles = new ArrayList<RoleEntity>();
+ }
+ roles.add(role);
+ }
+
+ public Map<String, String> getSmtpConfig() {
+ return smtpConfig;
+ }
+
+ public void setSmtpConfig(Map<String, String> smtpConfig) {
+ this.smtpConfig = smtpConfig;
+ }
+ public Map<String, String> getSocialConfig() {
+ return socialConfig;
+ }
+ public void setSocialConfig(Map<String, String> socialConfig) {
+ this.socialConfig = socialConfig;
+ }
+ public Collection<RoleEntity> getDefaultRoles() {
+ return defaultRoles;
+ }
+ public void setDefaultRoles(Collection<RoleEntity> defaultRoles) {
+ this.defaultRoles = defaultRoles;
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmScopeMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmScopeMappingEntity.java
new file mode 100755
index 0000000..5800e9f
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmScopeMappingEntity.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="userHasRealmScope", query="select m from RealmScopeMappingEntity m where m.user = :user and m.role = :role and m.realm = :realm"),
+ @NamedQuery(name="userRealmScopeMappings", query="select m from RealmScopeMappingEntity m where m.user = :user and m.realm = :realm")
+})
+@Entity
+public class RealmScopeMappingEntity extends UserRoleMappingEntity {
+
+ @ManyToOne
+ protected RealmEntity realm;
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmUserRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmUserRoleMappingEntity.java
new file mode 100755
index 0000000..305ce8d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmUserRoleMappingEntity.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name="userHasRealmRole", query="select m from RealmUserRoleMappingEntity m where m.user = :user and m.role = :role and m.realm = :realm"),
+ @NamedQuery(name="userRealmMappings", query="select m from RealmUserRoleMappingEntity m where m.user = :user and m.realm = :realm")
+})
+@Entity
+public class RealmUserRoleMappingEntity extends UserRoleMappingEntity {
+
+ @ManyToOne
+ protected RealmEntity realm;
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java
new file mode 100755
index 0000000..40c11c9
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java
@@ -0,0 +1,61 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Entity
+public class RequiredCredentialEntity {
+ @Id
+ @GeneratedValue
+ protected String id;
+
+ protected String type;
+ protected boolean input;
+ protected boolean secret;
+ protected String formLabel;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public boolean isInput() {
+ return input;
+ }
+
+ public void setInput(boolean input) {
+ this.input = input;
+ }
+
+ public boolean isSecret() {
+ return secret;
+ }
+
+ public void setSecret(boolean secret) {
+ this.secret = secret;
+ }
+
+ public String getFormLabel() {
+ return formLabel;
+ }
+
+ public void setFormLabel(String formLabel) {
+ this.formLabel = formLabel;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
index 94bdf88..6b8fc5a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
@@ -1,20 +1,72 @@
package org.keycloak.models.jpa.entities;
+import org.keycloak.models.UserModel;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
+@NamedQueries({
+ @NamedQuery(name="getRealmUserByLoginName", query="select u from UserEntity u where u.loginName = :loginName and u.realm = :realm"),
+ @NamedQuery(name="getRealmUserByEmail", query="select u from UserEntity u where u.email = :email and u.realm = :realm"),
+ @NamedQuery(name="getRealmUserByLastName", query="select u from UserEntity u where u.lastName = :lastName and u.realm = :realm"),
+ @NamedQuery(name="getRealmUserByFirstLastName", query="select u from UserEntity u where u.firstName = :first and u.lastName = :last and u.realm = :realm")
+})
@Entity
public class UserEntity {
@Id
@GeneratedValue
- private String id;
+ protected String id;
+
+ protected String loginName;
+ protected String firstName;
+ protected String lastName;
+ protected String email;
+ protected boolean enabled;
+ protected boolean totp;
+ protected boolean emailVerified;
+
+ @ManyToOne
+ protected RealmEntity realm;
+
+ @ElementCollection
+ @MapKeyColumn(name="name")
+ @Column(name="value")
+ @CollectionTable
+ protected Map<String, String> attributes = new HashMap<String, String>();
+
+ @ElementCollection
+ @CollectionTable
+ protected Set<UserModel.RequiredAction> requiredActions = new HashSet<UserModel.RequiredAction>();
+
+ @ElementCollection
+ @CollectionTable
+ protected Set<String> webOrigins = new HashSet<String>();
+
+ @ElementCollection
+ @CollectionTable
+ protected Set<String> redirectUris = new HashSet<String>();
- private String loginName;
+ @OneToMany
+ protected Collection<CredentialEntity> credentials = new ArrayList<CredentialEntity>();
public String getId() {
return id;
@@ -31,4 +83,100 @@ public class UserEntity {
public void setLoginName(String loginName) {
this.loginName = loginName;
}
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isTotp() {
+ return totp;
+ }
+
+ public void setTotp(boolean totp) {
+ this.totp = totp;
+ }
+
+ public boolean isEmailVerified() {
+ return emailVerified;
+ }
+
+ public void setEmailVerified(boolean emailVerified) {
+ this.emailVerified = emailVerified;
+ }
+
+ public Map<String, String> getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(Map<String, String> attributes) {
+ this.attributes = attributes;
+ }
+
+ public Set<UserModel.RequiredAction> getRequiredActions() {
+ return requiredActions;
+ }
+
+ public void setRequiredActions(Set<UserModel.RequiredAction> requiredActions) {
+ this.requiredActions = requiredActions;
+ }
+
+ public Set<String> getWebOrigins() {
+ return webOrigins;
+ }
+
+ public void setWebOrigins(Set<String> webOrigins) {
+ this.webOrigins = webOrigins;
+ }
+
+ public Set<String> getRedirectUris() {
+ return redirectUris;
+ }
+
+ public void setRedirectUris(Set<String> redirectUris) {
+ this.redirectUris = redirectUris;
+ }
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+
+ public Collection<CredentialEntity> getCredentials() {
+ return credentials;
+ }
+
+ public void setCredentials(Collection<CredentialEntity> credentials) {
+ this.credentials = credentials;
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java
index 51099df..2befc8d 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java
@@ -1,24 +1,23 @@
package org.keycloak.models.jpa.entities;
-import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
+import javax.persistence.MappedSuperclass;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-@Entity
-public class UserRoleMappingEntity {
+@MappedSuperclass
+public abstract class UserRoleMappingEntity {
@Id
@GeneratedValue
- private long id;
-
+ protected long id;
@ManyToOne
- private UserEntity user;
+ protected UserEntity user;
@ManyToOne
- private RoleEntity role;
+ protected RoleEntity role;
public long getId() {
return id;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
new file mode 100755
index 0000000..13d26d3
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
@@ -0,0 +1,74 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.RealmEntity;
+import org.keycloak.models.utils.KeycloakSessionUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaKeycloakSession implements KeycloakSession {
+ protected EntityManager em;
+
+ public JpaKeycloakSession(EntityManager em) {
+ this.em = em;
+ }
+
+ @Override
+ public KeycloakTransaction getTransaction() {
+ return new JpaKeycloakTransaction(em);
+ }
+
+ @Override
+ public RealmModel createRealm(String name) {
+ return createRealm(KeycloakSessionUtils.generateId(), name);
+ }
+
+ @Override
+ public RealmModel createRealm(String id, String name) {
+ RealmEntity realm = new RealmEntity();
+ realm.setName(name);
+ realm.setId(id);
+ em.persist(realm);
+ em.flush();
+ return new RealmAdapter(em, realm);
+ }
+
+ @Override
+ public RealmModel getRealm(String id) {
+ RealmEntity realm = em.find(RealmEntity.class, id);
+ if (realm == null) return null;
+ return new RealmAdapter(em, realm);
+ }
+
+ @Override
+ public List<RealmModel> getRealms(UserModel admin) {
+ TypedQuery<RealmEntity> query = em.createQuery("select r from RealmEntity r", RealmEntity.class);
+ List<RealmEntity> entities = query.getResultList();
+ List<RealmModel> realms = new ArrayList<RealmModel>();
+ for (RealmEntity entity : entities) {
+ realms.add(new RealmAdapter(em, entity));
+ }
+ return realms;
+ }
+
+ @Override
+ public void deleteRealm(RealmModel realm) {
+ throw new RuntimeException("Not Implemented Yet");
+ }
+
+ @Override
+ public void close() {
+ if (em.getTransaction().isActive()) em.getTransaction().rollback();
+ if (em.isOpen()) em.close();
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
new file mode 100755
index 0000000..67ba543
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
@@ -0,0 +1,28 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+import javax.persistence.EntityManagerFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
+ protected EntityManagerFactory factory;
+
+ public JpaKeycloakSessionFactory(EntityManagerFactory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ public KeycloakSession createSession() {
+ return new JpaKeycloakSession(factory.createEntityManager());
+ }
+
+ @Override
+ public void close() {
+ factory.close();
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java
new file mode 100755
index 0000000..6e7f3f3
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java
@@ -0,0 +1,48 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.KeycloakTransaction;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaKeycloakTransaction implements KeycloakTransaction {
+
+ protected EntityManager em;
+
+ public JpaKeycloakTransaction(EntityManager em) {
+ this.em = em;
+ }
+
+ @Override
+ public void begin() {
+ em.getTransaction().begin();
+ }
+
+ @Override
+ public void commit() {
+ em.getTransaction().commit();
+ }
+
+ @Override
+ public void rollback() {
+ em.getTransaction().rollback();
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ em.getTransaction().setRollbackOnly();
+ }
+
+ @Override
+ public boolean getRollbackOnly() {
+ return em.getTransaction().getRollbackOnly();
+ }
+
+ @Override
+ public boolean isActive() {
+ return em.getTransaction().isActive();
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java
new file mode 100755
index 0000000..1c5f743
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java
@@ -0,0 +1,20 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ModelProvider;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaModelProvider implements ModelProvider {
+ @Override
+ public KeycloakSessionFactory createFactory() {
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store");
+ return new JpaKeycloakSessionFactory(emf);
+
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java
new file mode 100755
index 0000000..fd2afcc
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java
@@ -0,0 +1,32 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.OAuthClientEntity;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthClientAdapter implements OAuthClientModel {
+ protected OAuthClientEntity entity;
+
+ public OAuthClientAdapter(OAuthClientEntity entity) {
+ this.entity = entity;
+ }
+
+ public OAuthClientEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public UserModel getOAuthAgent() {
+ return new UserAdapter(entity.getAgent());
+ }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
new file mode 100755
index 0000000..8eb89d5
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -0,0 +1,955 @@
+package org.keycloak.models.jpa;
+
+import org.bouncycastle.openssl.PEMWriter;
+import org.keycloak.PemUtils;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.ApplicationEntity;
+import org.keycloak.models.jpa.entities.CredentialEntity;
+import org.keycloak.models.jpa.entities.OAuthClientEntity;
+import org.keycloak.models.jpa.entities.RealmEntity;
+import org.keycloak.models.jpa.entities.RealmScopeMappingEntity;
+import org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity;
+import org.keycloak.models.jpa.entities.RequiredCredentialEntity;
+import org.keycloak.models.jpa.entities.RoleEntity;
+import org.keycloak.models.jpa.entities.SocialLinkEntity;
+import org.keycloak.models.jpa.entities.UserEntity;
+import org.keycloak.models.utils.SHAPasswordEncoder;
+import org.keycloak.models.utils.TimeBasedOTP;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmAdapter implements RealmModel {
+ protected RealmEntity realm;
+ protected EntityManager em;
+ protected volatile transient PublicKey publicKey;
+ protected volatile transient PrivateKey privateKey;
+
+ public RealmAdapter(EntityManager em, RealmEntity realm) {
+ this.em = em;
+ this.realm = realm;
+ }
+
+ @Override
+ public String getId() {
+ return realm.getId();
+ }
+
+ @Override
+ public String getName() {
+ return realm.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ realm.setName(name);
+ em.flush();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return realm.isEnabled();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ realm.setEnabled(enabled);
+ em.flush();
+ }
+
+ @Override
+ public boolean isSslNotRequired() {
+ return realm.isSslNotRequired();
+ }
+
+ @Override
+ public void setSslNotRequired(boolean sslNotRequired) {
+ realm.setSslNotRequired(sslNotRequired);
+ em.flush();
+ }
+
+ @Override
+ public boolean isCookieLoginAllowed() {
+ return realm.isCookieLoginAllowed();
+ }
+
+ @Override
+ public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
+ realm.setCookieLoginAllowed(cookieLoginAllowed);
+ em.flush();
+ }
+
+ @Override
+ public boolean isRegistrationAllowed() {
+ return realm.isRegistrationAllowed();
+ }
+
+ @Override
+ public void setRegistrationAllowed(boolean registrationAllowed) {
+ realm.setRegistrationAllowed(registrationAllowed);
+ em.flush();
+ }
+
+ @Override
+ public boolean isVerifyEmail() {
+ return realm.isVerifyEmail();
+ }
+
+ @Override
+ public void setVerifyEmail(boolean verifyEmail) {
+ realm.setVerifyEmail(verifyEmail);
+ em.flush();
+ }
+
+ @Override
+ public boolean isResetPasswordAllowed() {
+ return realm.isResetPasswordAllowed();
+ }
+
+ @Override
+ public void setResetPasswordAllowed(boolean resetPasswordAllowed) {
+ realm.setResetPasswordAllowed(resetPasswordAllowed);
+ em.flush();
+ }
+
+ @Override
+ public int getTokenLifespan() {
+ return realm.getTokenLifespan();
+ }
+
+ @Override
+ public void setTokenLifespan(int tokenLifespan) {
+ realm.setTokenLifespan(tokenLifespan);
+ em.flush();
+ }
+
+ @Override
+ public int getAccessCodeLifespan() {
+ return realm.getAccessCodeLifespan();
+ }
+
+ @Override
+ public void setAccessCodeLifespan(int accessCodeLifespan) {
+ realm.setAccessCodeLifespan(accessCodeLifespan);
+ em.flush();
+ }
+
+ @Override
+ public int getAccessCodeLifespanUserAction() {
+ return realm.getAccessCodeLifespanUserAction();
+ }
+
+ @Override
+ public void setAccessCodeLifespanUserAction(int accessCodeLifespanUserAction) {
+ realm.setAccessCodeLifespanUserAction(accessCodeLifespanUserAction);
+ em.flush();
+ }
+
+ @Override
+ public String getPublicKeyPem() {
+ return realm.getPublicKeyPem();
+ }
+
+ @Override
+ public void setPublicKeyPem(String publicKeyPem) {
+ realm.setPublicKeyPem(publicKeyPem);
+ em.flush();
+ }
+
+ @Override
+ public String getPrivateKeyPem() {
+ return realm.getPrivateKeyPem();
+ }
+
+ @Override
+ public void setPrivateKeyPem(String privateKeyPem) {
+ realm.setPrivateKeyPem(privateKeyPem);
+ em.flush();
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ if (publicKey != null) return publicKey;
+ String pem = getPublicKeyPem();
+ if (pem != null) {
+ try {
+ publicKey = PemUtils.decodePublicKey(pem);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return publicKey;
+ }
+
+ @Override
+ public void setPublicKey(PublicKey publicKey) {
+ this.publicKey = publicKey;
+ StringWriter writer = new StringWriter();
+ PEMWriter pemWriter = new PEMWriter(writer);
+ try {
+ pemWriter.writeObject(publicKey);
+ pemWriter.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ String s = writer.toString();
+ setPublicKeyPem(PemUtils.removeBeginEnd(s));
+ }
+
+ @Override
+ public PrivateKey getPrivateKey() {
+ if (privateKey != null) return privateKey;
+ String pem = getPrivateKeyPem();
+ if (pem != null) {
+ try {
+ privateKey = PemUtils.decodePrivateKey(pem);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return privateKey;
+ }
+
+ @Override
+ public void setPrivateKey(PrivateKey privateKey) {
+ this.privateKey = privateKey;
+ StringWriter writer = new StringWriter();
+ PEMWriter pemWriter = new PEMWriter(writer);
+ try {
+ pemWriter.writeObject(privateKey);
+ pemWriter.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ String s = writer.toString();
+ setPrivateKeyPem(PemUtils.removeBeginEnd(s));
+ }
+
+ protected RequiredCredentialModel initRequiredCredentialModel(String type) {
+ RequiredCredentialModel model = RequiredCredentialModel.BUILT_IN.get(type);
+ if (model == null) {
+ throw new RuntimeException("Unknown credential type " + type);
+ }
+ return model;
+ }
+
+ @Override
+ public void addRequiredCredential(String type) {
+ RequiredCredentialModel model = initRequiredCredentialModel(type);
+ addRequiredCredential(model);
+ em.flush();
+ }
+
+ public void addRequiredCredential(RequiredCredentialModel model) {
+ RequiredCredentialEntity entity = new RequiredCredentialEntity();
+ entity.setInput(model.isInput());
+ entity.setSecret(model.isSecret());
+ entity.setType(model.getType());
+ entity.setFormLabel(model.getFormLabel());
+ em.persist(entity);
+ realm.getRequiredCredentials().add(entity);
+ em.flush();
+ }
+
+ @Override
+ public void updateRequiredCredentials(Set<String> creds) {
+ Collection<RequiredCredentialEntity> relationships = realm.getRequiredCredentials();
+ if (relationships == null) relationships = new ArrayList<RequiredCredentialEntity>();
+
+ Set<String> already = new HashSet<String>();
+ List<RequiredCredentialEntity> remove = new ArrayList<RequiredCredentialEntity>();
+ for (RequiredCredentialEntity rel : relationships) {
+ if (!creds.contains(rel.getType())) {
+ remove.add(rel);
+ } else {
+ already.add(rel.getType());
+ }
+ }
+ for (RequiredCredentialEntity entity : remove) {
+ relationships.remove(entity);
+ em.remove(entity);
+ }
+ for (String cred : creds) {
+ if (!already.contains(cred)) {
+ addRequiredCredential(cred);
+ }
+ }
+ em.flush();
+ }
+
+
+ @Override
+ public List<RequiredCredentialModel> getRequiredCredentials() {
+ List<RequiredCredentialModel> requiredCredentialModels = new ArrayList<RequiredCredentialModel>();
+ Collection<RequiredCredentialEntity> entities = realm.getRequiredCredentials();
+ if (entities == null) return requiredCredentialModels;
+ for (RequiredCredentialEntity entity : entities) {
+ RequiredCredentialModel model = new RequiredCredentialModel();
+ model.setFormLabel(entity.getFormLabel());
+ model.setType(entity.getType());
+ model.setSecret(entity.isSecret());
+ model.setInput(entity.isInput());
+ requiredCredentialModels.add(model);
+ }
+ return requiredCredentialModels; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<RequiredCredentialModel> getRequiredApplicationCredentials() {
+ List<RequiredCredentialModel> requiredCredentialModels = new ArrayList<RequiredCredentialModel>();
+ Collection<RequiredCredentialEntity> entities = realm.getRequiredApplicationCredentials();
+ if (entities == null) return requiredCredentialModels;
+ for (RequiredCredentialEntity entity : entities) {
+ RequiredCredentialModel model = new RequiredCredentialModel();
+ model.setFormLabel(entity.getFormLabel());
+ model.setType(entity.getType());
+ model.setSecret(entity.isSecret());
+ model.setInput(entity.isInput());
+ requiredCredentialModels.add(model);
+ }
+ return requiredCredentialModels; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<RequiredCredentialModel> getRequiredOAuthClientCredentials() {
+ List<RequiredCredentialModel> requiredCredentialModels = new ArrayList<RequiredCredentialModel>();
+ Collection<RequiredCredentialEntity> entities = realm.getRequiredOAuthClientCredentials();
+ if (entities == null) return requiredCredentialModels;
+ for (RequiredCredentialEntity entity : entities) {
+ RequiredCredentialModel model = new RequiredCredentialModel();
+ model.setFormLabel(entity.getFormLabel());
+ model.setType(entity.getType());
+ model.setSecret(entity.isSecret());
+ model.setInput(entity.isInput());
+ requiredCredentialModels.add(model);
+ }
+ return requiredCredentialModels; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addRequiredOAuthClientCredential(RequiredCredentialModel model) {
+ RequiredCredentialEntity entity = new RequiredCredentialEntity();
+ entity.setInput(model.isInput());
+ entity.setSecret(model.isSecret());
+ entity.setType(model.getType());
+ entity.setFormLabel(model.getFormLabel());
+ em.persist(entity);
+ realm.getRequiredOAuthClientCredentials().add(entity);
+ em.flush();
+ }
+
+ @Override
+ public void addRequiredOAuthClientCredential(String type) {
+ RequiredCredentialModel model = initRequiredCredentialModel(type);
+ addRequiredOAuthClientCredential(model);
+ em.flush();
+ }
+
+ public void addRequiredResourceCredential(RequiredCredentialModel model) {
+ RequiredCredentialEntity entity = new RequiredCredentialEntity();
+ entity.setInput(model.isInput());
+ entity.setSecret(model.isSecret());
+ entity.setType(model.getType());
+ entity.setFormLabel(model.getFormLabel());
+ em.persist(entity);
+ realm.getRequiredApplicationCredentials().add(entity);
+ em.flush();
+ }
+
+ @Override
+ public void addRequiredResourceCredential(String type) {
+ RequiredCredentialModel model = initRequiredCredentialModel(type);
+ addRequiredResourceCredential(model);
+ em.flush();
+ }
+
+ @Override
+ public void updateRequiredOAuthClientCredentials(Set<String> creds) {
+ Collection<RequiredCredentialEntity> relationships = realm.getRequiredOAuthClientCredentials();
+ if (relationships == null) relationships = new ArrayList<RequiredCredentialEntity>();
+
+ Set<String> already = new HashSet<String>();
+ List<RequiredCredentialEntity> remove = new ArrayList<RequiredCredentialEntity>();
+ for (RequiredCredentialEntity rel : relationships) {
+ if (!creds.contains(rel.getType())) {
+ remove.add(rel);
+ } else {
+ already.add(rel.getType());
+ }
+ }
+ for (RequiredCredentialEntity entity : remove) {
+ relationships.remove(entity);
+ em.remove(entity);
+ }
+ for (String cred : creds) {
+ if (!already.contains(cred)) {
+ addRequiredOAuthClientCredential(cred);
+ }
+ }
+ em.flush();
+ }
+
+ @Override
+ public void updateRequiredApplicationCredentials(Set<String> creds) {
+ Collection<RequiredCredentialEntity> relationships = realm.getRequiredApplicationCredentials();
+ if (relationships == null) relationships = new ArrayList<RequiredCredentialEntity>();
+
+ Set<String> already = new HashSet<String>();
+ List<RequiredCredentialEntity> remove = new ArrayList<RequiredCredentialEntity>();
+ for (RequiredCredentialEntity rel : relationships) {
+ if (!creds.contains(rel.getType())) {
+ remove.add(rel);
+ } else {
+ already.add(rel.getType());
+ }
+ }
+ for (RequiredCredentialEntity entity : remove) {
+ relationships.remove(entity);
+ em.remove(entity);
+ }
+ for (String cred : creds) {
+ if (!already.contains(cred)) {
+ addRequiredResourceCredential(cred);
+ }
+ }
+ em.flush();
+ }
+
+ @Override
+ public UserModel getUser(String name) {
+ TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByLoginName", UserEntity.class);
+ query.setParameter("loginName", name);
+ query.setParameter("realm", realm);
+ List<UserEntity> results = query.getResultList();
+ if (results.size() == 0) return null;
+ return new UserAdapter(results.get(0));
+ }
+
+ @Override
+ public UserModel addUser(String username) {
+ UserEntity entity = new UserEntity();
+ entity.setLoginName(username);
+ entity.setRealm(realm);
+ em.persist(entity);
+ em.flush();
+ return new UserAdapter(entity);
+ }
+
+ @Override
+ public List<String> getDefaultRoles() {
+ Collection<RoleEntity> entities = realm.getDefaultRoles();
+ List<String> roles = new ArrayList<String>();
+ if (entities == null) return roles;
+ for (RoleEntity entity : entities) {
+ roles.add(entity.getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public void addDefaultRole(String name) {
+ RoleModel role = getRole(name);
+ if (role == null) {
+ role = addRole(name);
+ }
+ Collection<RoleEntity> entities = realm.getDefaultRoles();
+ for (RoleEntity entity : entities) {
+ if (entity.getId().equals(role.getId())) {
+ return;
+ }
+ }
+ entities.add(((RoleAdapter) role).getRole());
+ em.flush();
+ }
+
+ public static boolean contains(String str, String[] array) {
+ for (String s : array) {
+ if (str.equals(s)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void updateDefaultRoles(String[] defaultRoles) {
+ Collection<RoleEntity> entities = realm.getDefaultRoles();
+ Set<String> already = new HashSet<String>();
+ List<RoleEntity> remove = new ArrayList<RoleEntity>();
+ for (RoleEntity rel : entities) {
+ if (!contains(rel.getName(), defaultRoles)) {
+ remove.add(rel);
+ } else {
+ already.add(rel.getName());
+ }
+ }
+ for (RoleEntity entity : remove) {
+ entities.remove(entity);
+ }
+ em.flush();
+ for (String roleName : defaultRoles) {
+ if (!already.contains(roleName)) {
+ addDefaultRole(roleName);
+ }
+ }
+ em.flush();
+ }
+
+ @Override
+ public Map<String, ApplicationModel> getApplicationNameMap() {
+ Map<String, ApplicationModel> map = new HashMap<String, ApplicationModel>();
+ for (ApplicationModel app : getApplications()) {
+ map.put(app.getName(), app);
+ }
+ return map; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<ApplicationModel> getApplications() {
+ List<ApplicationModel> list = new ArrayList<ApplicationModel>();
+ if (realm.getApplications() == null) return list;
+ for (ApplicationEntity entity : realm.getApplications()) {
+ list.add(new ApplicationAdapter(em, entity));
+ }
+ return list;
+ }
+
+ @Override
+ public ApplicationModel addApplication(String name) {
+ ApplicationEntity applicationData = new ApplicationEntity();
+ UserEntity user = new UserEntity();
+ user.setLoginName(name);
+ user.setRealm(realm);
+ user.setEnabled(true);
+ em.persist(user);
+ applicationData.setApplicationUser(user);
+ applicationData.setName(name);
+ applicationData.setEnabled(true);
+ realm.getApplications().add(applicationData);
+ em.persist(applicationData);
+ em.flush();
+ ApplicationModel resource = new ApplicationAdapter(em, applicationData);
+ resource.addRole("*");
+ resource.addScopeMapping(new UserAdapter(user), "*");
+ em.flush();
+ return resource;
+ }
+
+ @Override
+ public ApplicationModel getApplicationById(String id) {
+ ApplicationEntity app = em.find(ApplicationEntity.class, id);
+ if (app == null) return null;
+ return new ApplicationAdapter(em, app);
+ }
+
+ @Override
+ public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
+ TypedQuery<UserEntity> query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
+ query.setParameter("realm", realm);
+ query.setParameter("socialProvider", socialLink.getSocialProvider());
+ query.setParameter("socialUsername", socialLink.getSocialUsername());
+ List<UserEntity> results = query.getResultList();
+ if (results.isEmpty()) {
+ return null;
+ } else if (results.size() > 1) {
+ throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
+ ", socialUsername=" + socialLink.getSocialUsername() + ", results=" + results);
+ } else {
+ UserEntity user = results.get(0);
+ return new UserAdapter(user);
+ }
+ }
+
+ @Override
+ public Set<SocialLinkModel> getSocialLinks(UserModel user) {
+ TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class);
+ query.setParameter("user", ((UserAdapter) user).getUser());
+ List<SocialLinkEntity> results = query.getResultList();
+ Set<SocialLinkModel> set = new HashSet<SocialLinkModel>();
+ for (SocialLinkEntity entity : results) {
+ set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUsername()));
+ }
+ return set;
+ }
+
+ @Override
+ public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
+ SocialLinkEntity entity = new SocialLinkEntity();
+ entity.setRealm(realm);
+ entity.setSocialProvider(socialLink.getSocialProvider());
+ entity.setSocialUsername(socialLink.getSocialUsername());
+ entity.setUser(((UserAdapter) user).getUser());
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public void removeSocialLink(UserModel user, SocialLinkModel socialLink) {
+ TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByAll", SocialLinkEntity.class);
+ query.setParameter("realm", realm);
+ query.setParameter("user", ((UserAdapter) user).getUser());
+ query.setParameter("socialProvider", socialLink.getSocialProvider());
+ query.setParameter("socialUsername", socialLink.getSocialUsername());
+ List<SocialLinkEntity> results = query.getResultList();
+ for (SocialLinkEntity entity : results) em.remove(entity);
+ em.flush();
+ }
+
+ @Override
+ public boolean isSocial() {
+ return realm.isSocial();
+ }
+
+ @Override
+ public void setSocial(boolean social) {
+ realm.setSocial(social);
+ em.flush();
+ }
+
+ @Override
+ public boolean isAutomaticRegistrationAfterSocialLogin() {
+ return realm.isAutomaticRegistrationAfterSocialLogin();
+ }
+
+ @Override
+ public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin) {
+ realm.setAutomaticRegistrationAfterSocialLogin(automaticRegistrationAfterSocialLogin);
+ em.flush();
+ }
+
+ @Override
+ public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
+ StringBuilder builder = new StringBuilder("select u from UserEntity u");
+ boolean first = true;
+ for (Map.Entry<String, String> entry : attributes.entrySet()) {
+ String attribute = null;
+ if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
+ attribute = "loginName";
+ } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
+ attribute = "firstName";
+ } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
+ attribute = "lastName";
+ } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
+ attribute = "email";
+ }
+ if (attribute == null) continue;
+ if (first) {
+ first = false;
+ builder.append(" where ");
+ } else {
+ builder.append(" and ");
+ }
+ builder.append(attribute).append("='").append(entry.getValue()).append("'");
+ }
+ TypedQuery<UserEntity> query = em.createQuery(builder.toString(), UserEntity.class);
+ List<UserEntity> results = query.getResultList();
+ List<UserModel> users = new ArrayList<UserModel>();
+ for (UserEntity entity : results) users.add(new UserAdapter(entity));
+ return users;
+ }
+
+ @Override
+ public OAuthClientModel addOAuthClient(String name) {
+ OAuthClientEntity data = new OAuthClientEntity();
+ UserEntity user = new UserEntity();
+ user.setLoginName(name);
+ user.setRealm(realm);
+ user.setEnabled(true);
+ em.persist(user);
+ data.setAgent(user);
+ data.setName(name);
+ data.setRealm(realm);
+ em.persist(data);
+ em.flush();
+ return new OAuthClientAdapter(data);
+ }
+
+ @Override
+ public OAuthClientModel getOAuthClient(String name) {
+ TypedQuery<OAuthClientEntity> query = em.createNamedQuery("findOAuthClientByUser", OAuthClientEntity.class);
+ query.setParameter("name", name);
+ query.setParameter("realm", realm);
+ List<OAuthClientEntity> entities = query.getResultList();
+ if (entities.size() == 0) return null;
+ return new OAuthClientAdapter(entities.get(0));
+ }
+
+ @Override
+ public List<OAuthClientModel> getOAuthClients() {
+ TypedQuery<OAuthClientEntity> query = em.createNamedQuery("findOAuthClientByRealm", OAuthClientEntity.class);
+ query.setParameter("realm", realm);
+ List<OAuthClientEntity> entities = query.getResultList();
+ List<OAuthClientModel> list = new ArrayList<OAuthClientModel>();
+ for (OAuthClientEntity entity : entities) list.add(new OAuthClientAdapter(entity));
+ return list;
+ }
+
+ @Override
+ public Map<String, String> getSmtpConfig() {
+ return realm.getSmtpConfig();
+ }
+
+ @Override
+ public void setSmtpConfig(Map<String, String> smtpConfig) {
+ realm.setSmtpConfig(smtpConfig);
+ em.flush();
+ }
+
+ @Override
+ public Map<String, String> getSocialConfig() {
+ return realm.getSocialConfig();
+ }
+
+ @Override
+ public void setSocialConfig(Map<String, String> socialConfig) {
+ realm.setSocialConfig(socialConfig);
+ em.flush();
+ }
+
+ @Override
+ public RoleModel getRole(String name) {
+ Collection<RoleEntity> roles = realm.getRoles();
+ if (roles == null) return null;
+ for (RoleEntity role : roles) {
+ if (role.getName().equals(name)) {
+ return new RoleAdapter(role);
+ }
+ }
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public RoleModel addRole(String name) {
+ RoleModel role = getRole(name);
+ if (role != null) return role;
+ RoleEntity entity = new RoleEntity();
+ entity.setName(name);
+ em.persist(entity);
+ realm.getRoles().add(entity);
+ em.flush();
+ return new RoleAdapter(entity);
+ }
+
+ @Override
+ public List<RoleModel> getRoles() {
+ ArrayList<RoleModel> list = new ArrayList<RoleModel>();
+ Collection<RoleEntity> roles = realm.getRoles();
+ if (roles == null) return list;
+ for (RoleEntity entity : roles) {
+ list.add(new RoleAdapter(entity));
+ }
+ return list;
+ }
+
+ @Override
+ public RoleModel getRoleById(String id) {
+ RoleEntity entity = em.find(RoleEntity.class, id);
+ if (entity == null) return null;
+ return new RoleAdapter(entity);
+ }
+
+ @Override
+ public boolean hasRole(UserModel user, RoleModel role) {
+ TypedQuery<RealmUserRoleMappingEntity> query = getRealmUserRoleMappingEntityTypedQuery((UserAdapter) user, (RoleAdapter) role);
+ return query.getResultList().size() > 0;
+ }
+
+ protected TypedQuery<RealmUserRoleMappingEntity> getRealmUserRoleMappingEntityTypedQuery(UserAdapter user, RoleAdapter role) {
+ TypedQuery<RealmUserRoleMappingEntity> query = em.createNamedQuery("userHasRealmRole", RealmUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("role", ((RoleAdapter)role).getRole());
+ query.setParameter("realm", realm);
+ return query;
+ }
+
+ @Override
+ public void grantRole(UserModel user, RoleModel role) {
+ if (hasRole(user, role)) return;
+ RealmUserRoleMappingEntity entity = new RealmUserRoleMappingEntity();
+ entity.setRealm(realm);
+ entity.setUser(((UserAdapter) user).getUser());
+ entity.setRole(((RoleAdapter)role).getRole());
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public List<RoleModel> getRoleMappings(UserModel user) {
+ TypedQuery<RealmUserRoleMappingEntity> query = em.createNamedQuery("userRealmMappings", RealmUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("realm", realm);
+ List<RealmUserRoleMappingEntity> entities = query.getResultList();
+ List<RoleModel> roles = new ArrayList<RoleModel>();
+ for (RealmUserRoleMappingEntity entity : entities) {
+ roles.add(new RoleAdapter(entity.getRole()));
+ }
+ return roles;
+ }
+
+ @Override
+ public Set<String> getRoleMappingValues(UserModel user) {
+ TypedQuery<RealmUserRoleMappingEntity> query = em.createNamedQuery("userRealmMappings", RealmUserRoleMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("realm", realm);
+ List<RealmUserRoleMappingEntity> entities = query.getResultList();
+ Set<String> roles = new HashSet<String>();
+ for (RealmUserRoleMappingEntity entity : entities) {
+ roles.add(entity.getRole().getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public void deleteRoleMapping(UserModel user, RoleModel role) {
+ TypedQuery<RealmUserRoleMappingEntity> query = getRealmUserRoleMappingEntityTypedQuery((UserAdapter) user, (RoleAdapter) role);
+ List<RealmUserRoleMappingEntity> results = query.getResultList();
+ if (results.size() == 0) return;
+ for (RealmUserRoleMappingEntity entity : results) {
+ em.remove(entity);
+ }
+ em.flush();
+ }
+
+ @Override
+ public boolean hasRole(UserModel user, String roleName) {
+ RoleModel role = getRole(roleName);
+ if (role == null) return false;
+ return hasRole(user, role);
+ }
+
+ @Override
+ public void addScopeMapping(UserModel agent, String roleName) {
+ RoleModel role = getRole(roleName);
+ if (role == null) throw new RuntimeException("role does not exist");
+ addScopeMapping(agent, role);
+ em.flush();
+ }
+
+ @Override
+ public Set<String> getScopeMappingValues(UserModel agent) {
+ TypedQuery<RealmScopeMappingEntity> query = em.createNamedQuery("userRealmScopeMappings", RealmScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)agent).getUser());
+ query.setParameter("realm", realm);
+ List<RealmScopeMappingEntity> entities = query.getResultList();
+ Set<String> roles = new HashSet<String>();
+ for (RealmScopeMappingEntity entity : entities) {
+ roles.add(entity.getRole().getName());
+ }
+ return roles;
+ }
+
+ @Override
+ public List<RoleModel> getScopeMappings(UserModel agent) {
+ TypedQuery<RealmScopeMappingEntity> query = em.createNamedQuery("userRealmScopeMappings", RealmScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)agent).getUser());
+ query.setParameter("realm", realm);
+ List<RealmScopeMappingEntity> entities = query.getResultList();
+ List<RoleModel> roles = new ArrayList<RoleModel>();
+ for (RealmScopeMappingEntity entity : entities) {
+ roles.add(new RoleAdapter(entity.getRole()));
+ }
+ return roles;
+ }
+
+ @Override
+ public void addScopeMapping(UserModel agent, RoleModel role) {
+ if (hasScope(agent, role)) return;
+ RealmScopeMappingEntity entity = new RealmScopeMappingEntity();
+ entity.setRealm(realm);
+ entity.setUser(((UserAdapter) agent).getUser());
+ entity.setRole(((RoleAdapter)role).getRole());
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public void deleteScopeMapping(UserModel user, RoleModel role) {
+ TypedQuery<RealmScopeMappingEntity> query = getRealmScopeMappingQuery((UserAdapter) user, (RoleAdapter) role);
+ List<RealmScopeMappingEntity> results = query.getResultList();
+ if (results.size() == 0) return;
+ for (RealmScopeMappingEntity entity : results) {
+ em.remove(entity);
+ }
+ }
+
+ public boolean hasScope(UserModel user, RoleModel role) {
+ TypedQuery<RealmScopeMappingEntity> query = getRealmScopeMappingQuery((UserAdapter) user, (RoleAdapter) role);
+ return query.getResultList().size() > 0;
+ }
+
+
+ protected TypedQuery<RealmScopeMappingEntity> getRealmScopeMappingQuery(UserAdapter user, RoleAdapter role) {
+ TypedQuery<RealmScopeMappingEntity> query = em.createNamedQuery("userHasRealmScope", RealmScopeMappingEntity.class);
+ query.setParameter("user", ((UserAdapter)user).getUser());
+ query.setParameter("role", ((RoleAdapter)role).getRole());
+ query.setParameter("realm", realm);
+ return query;
+ }
+
+ @Override
+ public boolean validatePassword(UserModel user, String password) {
+ for (CredentialEntity cred : ((UserAdapter)user).getUser().getCredentials()) {
+ if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+ return new SHAPasswordEncoder(512).verify(password, cred.getValue());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean validateTOTP(UserModel user, String password, String token) {
+ if (!validatePassword(user, password)) return false;
+ for (CredentialEntity cred : ((UserAdapter)user).getUser().getCredentials()) {
+ if (cred.getType().equals(UserCredentialModel.TOTP)) {
+ return new TimeBasedOTP().validate(token, cred.getValue().getBytes());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void updateCredential(UserModel user, UserCredentialModel cred) {
+ CredentialEntity credentialEntity = null;
+ UserEntity userEntity = ((UserAdapter) user).getUser();
+ for (CredentialEntity entity : userEntity.getCredentials()) {
+ if (entity.getType().equals(cred.getType())) {
+ credentialEntity = entity;
+ }
+ }
+ if (credentialEntity == null) {
+ credentialEntity = new CredentialEntity();
+ credentialEntity.setType(cred.getType());
+ credentialEntity.setDevice(cred.getDevice());
+ credentialEntity.setUser(userEntity);
+ em.persist(credentialEntity);
+ userEntity.getCredentials().add(credentialEntity);
+ }
+ if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+ credentialEntity.setValue(new SHAPasswordEncoder(512).encode(cred.getValue()));
+ } else {
+ credentialEntity.setValue(cred.getValue());
+ }
+ credentialEntity.setDevice(cred.getDevice());
+ em.flush();
+ }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
new file mode 100755
index 0000000..5785dec
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -0,0 +1,49 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.jpa.entities.RoleEntity;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RoleAdapter implements RoleModel {
+ protected RoleEntity role;
+
+ public RoleAdapter(RoleEntity role) {
+ this.role = role;
+ }
+
+ public RoleEntity getRole() {
+ return role;
+ }
+
+ public void setRole(RoleEntity role) {
+ this.role = role;
+ }
+
+ @Override
+ public String getName() {
+ return role.getName();
+ }
+
+ @Override
+ public String getDescription() {
+ return role.getDescription();
+ }
+
+ @Override
+ public void setDescription(String description) {
+ role.setDescription(description);
+ }
+
+ @Override
+ public String getId() {
+ return role.getId();
+ }
+
+ @Override
+ public void setName(String name) {
+ role.setName(name);
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
new file mode 100755
index 0000000..9f822d8
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -0,0 +1,185 @@
+package org.keycloak.models.jpa;
+
+import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.UserEntity;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserAdapter implements UserModel {
+
+ protected UserEntity user;
+
+ public UserAdapter(UserEntity user) {
+ this.user = user;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ @Override
+ public String getLoginName() {
+ return user.getLoginName();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return user.isEnabled();
+ }
+
+ @Override
+ public boolean isTotp() {
+ return user.isTotp();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ user.setEnabled(enabled);
+ }
+
+ @Override
+ public void setAttribute(String name, String value) {
+ Map<String, String> attributes = user.getAttributes();
+ if (attributes == null) {
+ attributes = new HashMap<String, String>();
+ }
+ attributes.put(name, value);
+ user.setAttributes(attributes);
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ Map<String, String> attributes = user.getAttributes();
+ if (attributes == null) {
+ attributes = new HashMap<String, String>();
+ }
+ attributes.remove(name);
+ user.setAttributes(attributes);
+ }
+
+ @Override
+ public String getAttribute(String name) {
+ if (user.getAttributes() == null) return null;
+ return user.getAttributes().get(name);
+ }
+
+ @Override
+ public Map<String, String> getAttributes() {
+ Map<String, String> result = new HashMap<String, String>();
+ result.putAll(user.getAttributes());
+ return result;
+ }
+
+ @Override
+ public Set<RequiredAction> getRequiredActions() {
+ Set<RequiredAction> result = new HashSet<RequiredAction>();
+ result.addAll(user.getRequiredActions());
+ return result;
+ }
+
+ @Override
+ public void addRequiredAction(RequiredAction action) {
+ user.getRequiredActions().add(action);
+ }
+
+ @Override
+ public void removeRequiredAction(RequiredAction action) {
+ user.getRequiredActions().remove(action);
+ }
+
+ @Override
+ public Set<String> getWebOrigins() {
+ Set<String> result = new HashSet<String>();
+ result.addAll(user.getWebOrigins());
+ return result;
+ }
+
+ @Override
+ public void setWebOrigins(Set<String> webOrigins) {
+ user.setWebOrigins(webOrigins);
+ }
+
+ @Override
+ public void addWebOrigin(String webOrigin) {
+ user.getWebOrigins().add(webOrigin);
+ }
+
+ @Override
+ public void removeWebOrigin(String webOrigin) {
+ user.getWebOrigins().remove(webOrigin);
+ }
+
+ @Override
+ public Set<String> getRedirectUris() {
+ Set<String> result = new HashSet<String>();
+ result.addAll(user.getRedirectUris());
+ return result;
+ }
+
+ @Override
+ public void setRedirectUris(Set<String> redirectUris) {
+ user.setRedirectUris(redirectUris);
+ }
+
+ @Override
+ public void addRedirectUri(String redirectUri) {
+ user.getRedirectUris().add(redirectUri);
+ }
+
+ @Override
+ public void removeRedirectUri(String redirectUri) {
+ user.getRedirectUris().remove(redirectUri);
+ }
+
+ @Override
+ public String getFirstName() {
+ return user.getFirstName();
+ }
+
+ @Override
+ public void setFirstName(String firstName) {
+ user.setFirstName(firstName);
+ }
+
+ @Override
+ public String getLastName() {
+ return user.getLastName();
+ }
+
+ @Override
+ public void setLastName(String lastName) {
+ user.setLastName(lastName);
+ }
+
+ @Override
+ public String getEmail() {
+ return user.getEmail();
+ }
+
+ @Override
+ public void setEmail(String email) {
+ user.setEmail(email);
+ }
+
+ @Override
+ public boolean isEmailVerified() {
+ return user.isEmailVerified();
+ }
+
+ @Override
+ public void setEmailVerified(boolean verified) {
+ user.setEmailVerified(verified);
+ }
+
+ @Override
+ public void setTotp(boolean totp) {
+ user.setTotp(totp);
+ }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/api/NoSQL.java b/model/mongo/src/main/java/org/keycloak/models/mongo/api/NoSQL.java
old mode 100644
new mode 100755
index 3bc62a5..0a63606
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/api/NoSQL.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/api/NoSQL.java
@@ -1,10 +1,9 @@
package org.keycloak.models.mongo.api;
-import java.util.List;
-
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.api.query.NoSQLQueryBuilder;
-import org.picketlink.common.properties.Property;
+
+import java.util.List;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/api/types/TypeConverter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/api/types/TypeConverter.java
old mode 100644
new mode 100755
index a7c12c0..e097930
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/api/types/TypeConverter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/api/types/TypeConverter.java
@@ -3,8 +3,6 @@ package org.keycloak.models.mongo.api.types;
import java.util.HashMap;
import java.util.Map;
-import org.picketlink.common.reflection.Reflections;
-
/**
* Registry of converters, which allow to convert application object to database objects. TypeConverter is main entry point to be used by application.
* Application can create instance of TypeConverter and then register required Converter objects.
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBImpl.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBImpl.java
old mode 100644
new mode 100755
index 09ca78e..6bacedb
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBImpl.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBImpl.java
@@ -1,12 +1,5 @@
package org.keycloak.models.mongo.impl;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
@@ -24,10 +17,10 @@ import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.api.query.NoSQLQueryBuilder;
import org.keycloak.models.mongo.api.types.Converter;
import org.keycloak.models.mongo.api.types.TypeConverter;
-import org.keycloak.models.mongo.impl.types.EnumToStringConverter;
-import org.keycloak.models.mongo.impl.types.ListConverter;
import org.keycloak.models.mongo.impl.types.BasicDBListConverter;
import org.keycloak.models.mongo.impl.types.BasicDBObjectConverter;
+import org.keycloak.models.mongo.impl.types.EnumToStringConverter;
+import org.keycloak.models.mongo.impl.types.ListConverter;
import org.keycloak.models.mongo.impl.types.NoSQLObjectConverter;
import org.keycloak.models.mongo.impl.types.SimpleConverter;
import org.keycloak.models.mongo.impl.types.StringToEnumConverter;
@@ -35,6 +28,13 @@ import org.picketlink.common.properties.Property;
import org.picketlink.common.properties.query.AnnotatedPropertyCriteria;
import org.picketlink.common.properties.query.PropertyQueries;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBQueryBuilder.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBQueryBuilder.java
old mode 100644
new mode 100755
index f56c799..2d1f61d
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBQueryBuilder.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoDBQueryBuilder.java
@@ -1,13 +1,13 @@
package org.keycloak.models.mongo.impl;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
import com.mongodb.BasicDBObject;
import org.bson.types.ObjectId;
import org.keycloak.models.mongo.api.query.NoSQLQueryBuilder;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/ObjectInfo.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/ObjectInfo.java
old mode 100644
new mode 100755
index ae548a6..b511626
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/ObjectInfo.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/ObjectInfo.java
@@ -1,14 +1,14 @@
package org.keycloak.models.mongo.impl;
+import org.keycloak.models.mongo.api.NoSQLObject;
+import org.picketlink.common.properties.Property;
+
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.keycloak.models.mongo.api.NoSQLObject;
-import org.picketlink.common.properties.Property;
-
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBListConverter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBListConverter.java
old mode 100644
new mode 100755
index 896257f..04824ba
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBListConverter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBListConverter.java
@@ -1,12 +1,12 @@
package org.keycloak.models.mongo.impl.types;
-import java.util.ArrayList;
-
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import org.keycloak.models.mongo.api.types.Converter;
import org.keycloak.models.mongo.api.types.TypeConverter;
+import java.util.ArrayList;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/ListConverter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/ListConverter.java
old mode 100644
new mode 100755
index 8b72ca2..49fb627
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/ListConverter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/ListConverter.java
@@ -1,12 +1,12 @@
package org.keycloak.models.mongo.impl.types;
-import java.util.List;
-
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import org.keycloak.models.mongo.api.types.Converter;
import org.keycloak.models.mongo.api.types.TypeConverter;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/NoSQLObjectConverter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/NoSQLObjectConverter.java
old mode 100644
new mode 100755
index f7be7ae..35596a9
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/NoSQLObjectConverter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/NoSQLObjectConverter.java
@@ -1,8 +1,5 @@
package org.keycloak.models.mongo.impl.types;
-import java.util.Collection;
-import java.util.Map;
-
import com.mongodb.BasicDBObject;
import org.keycloak.models.mongo.api.AttributedNoSQLObject;
import org.keycloak.models.mongo.api.NoSQLObject;
@@ -12,6 +9,9 @@ import org.keycloak.models.mongo.impl.MongoDBImpl;
import org.keycloak.models.mongo.impl.ObjectInfo;
import org.picketlink.common.properties.Property;
+import java.util.Collection;
+import java.util.Map;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
old mode 100644
new mode 100755
index 49bcd31..c1a4dd2
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
@@ -1,10 +1,5 @@
package org.keycloak.models.mongo.keycloak.adapters;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
@@ -14,6 +9,11 @@ import org.keycloak.models.mongo.keycloak.data.ApplicationData;
import org.keycloak.models.mongo.keycloak.data.RoleData;
import org.keycloak.models.mongo.keycloak.data.UserData;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -281,4 +281,19 @@ public class ApplicationAdapter implements ApplicationModel {
}
return result;
}
+
+ @Override
+ public List<String> getDefaultRoles() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void addDefaultRole(String name) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void updateDefaultRoles(String[] defaultRoles) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoDBSessionFactory.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoDBSessionFactory.java
old mode 100644
new mode 100755
index b1ac509..f964605
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoDBSessionFactory.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoDBSessionFactory.java
@@ -1,7 +1,5 @@
package org.keycloak.models.mongo.keycloak.adapters;
-import java.net.UnknownHostException;
-
import com.mongodb.DB;
import com.mongodb.MongoClient;
import org.jboss.logging.Logger;
@@ -9,6 +7,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.NoSQLObject;
+import org.keycloak.models.mongo.impl.MongoDBImpl;
import org.keycloak.models.mongo.keycloak.data.ApplicationData;
import org.keycloak.models.mongo.keycloak.data.OAuthClientData;
import org.keycloak.models.mongo.keycloak.data.RealmData;
@@ -16,10 +15,11 @@ import org.keycloak.models.mongo.keycloak.data.RequiredCredentialData;
import org.keycloak.models.mongo.keycloak.data.RoleData;
import org.keycloak.models.mongo.keycloak.data.SocialLinkData;
import org.keycloak.models.mongo.keycloak.data.UserData;
-import org.keycloak.models.mongo.impl.MongoDBImpl;
import org.keycloak.models.mongo.keycloak.data.credentials.OTPData;
import org.keycloak.models.mongo.keycloak.data.credentials.PasswordData;
+import java.net.UnknownHostException;
+
/**
* NoSQL implementation based on MongoDB
*
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/NoSQLSession.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/NoSQLSession.java
old mode 100644
new mode 100755
index 2bc413d..bbd5ea4
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/NoSQLSession.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/NoSQLSession.java
@@ -1,17 +1,17 @@
package org.keycloak.models.mongo.keycloak.adapters;
-import java.util.ArrayList;
-import java.util.List;
-
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.keycloak.data.RealmData;
-import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.utils.KeycloakSessionUtils;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
old mode 100644
new mode 100755
index 34f455e..d522db9
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
@@ -41,14 +41,4 @@ public class OAuthClientAdapter implements OAuthClientModel {
return oauthAgent;
}
- @Override
- public String getBaseUrl() {
- return delegate.getBaseUrl();
- }
-
- @Override
- public void setBaseUrl(String base) {
- delegate.setBaseUrl(base);
- noSQL.saveObject(delegate);
- }
}
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
old mode 100644
new mode 100755
index 837f985..391334a
--- 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
@@ -1,16 +1,5 @@
package org.keycloak.models.mongo.keycloak.adapters;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import org.bouncycastle.openssl.PEMWriter;
import org.keycloak.PemUtils;
import org.keycloak.models.ApplicationModel;
@@ -21,21 +10,31 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.mongo.api.query.NoSQLQueryBuilder;
-import org.keycloak.models.mongo.keycloak.data.OAuthClientData;
-import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
+import org.keycloak.models.mongo.api.query.NoSQLQueryBuilder;
import org.keycloak.models.mongo.keycloak.credentials.PasswordCredentialHandler;
import org.keycloak.models.mongo.keycloak.credentials.TOTPCredentialHandler;
import org.keycloak.models.mongo.keycloak.data.ApplicationData;
+import org.keycloak.models.mongo.keycloak.data.OAuthClientData;
import org.keycloak.models.mongo.keycloak.data.RealmData;
import org.keycloak.models.mongo.keycloak.data.RequiredCredentialData;
import org.keycloak.models.mongo.keycloak.data.RoleData;
import org.keycloak.models.mongo.keycloak.data.SocialLinkData;
import org.keycloak.models.mongo.keycloak.data.UserData;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.picketlink.idm.credential.Credentials;
-import org.picketlink.idm.model.sample.User;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -597,20 +596,6 @@ public class RealmAdapter implements RealmModel {
}
@Override
- public boolean isRealmAdmin(UserModel agent) {
- List<String> realmAdmins = realm.getRealmAdmins();
- String userId = ((UserAdapter)agent).getUser().getId();
- return realmAdmins.contains(userId);
- }
-
- @Override
- public void addRealmAdmin(UserModel agent) {
- UserData userData = ((UserAdapter)agent).getUser();
-
- noSQL.pushItemToList(realm, "realmAdmins", userData.getId());
- }
-
- @Override
public RoleModel getRoleById(String id) {
RoleData role = noSQL.loadObject(RoleData.class, id);
if (role == null) {
@@ -859,4 +844,24 @@ public class RealmAdapter implements RealmModel {
}
return userModels;
}
+
+ @Override
+ public Map<String, String> getSmtpConfig() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void setSmtpConfig(Map<String, String> smtpConfig) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public Map<String, String> getSocialConfig() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void setSocialConfig(Map<String, String> socialConfig) {
+ throw new RuntimeException("Not implemented");
+ }
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
old mode 100644
new mode 100755
index c047361..3b20848
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -1,15 +1,15 @@
package org.keycloak.models.mongo.keycloak.adapters;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.mongo.api.NoSQL;
+import org.keycloak.models.mongo.keycloak.data.UserData;
+
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.mongo.api.NoSQL;
-import org.keycloak.models.mongo.keycloak.data.UserData;
-
/**
* Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl)
*
@@ -149,4 +149,44 @@ public class UserAdapter implements UserModel {
user.setTotp(totp);
noSQL.saveObject(user);
}
+
+ @Override
+ public Set<String> getWebOrigins() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void setWebOrigins(Set<String> webOrigins) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void addWebOrigin(String webOrigin) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void removeWebOrigin(String webOrigin) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Set<String> getRedirectUris() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void setRedirectUris(Set<String> redirectUris) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void addRedirectUri(String redirectUri) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void removeRedirectUri(String redirectUri) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/PasswordCredentialHandler.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/PasswordCredentialHandler.java
old mode 100644
new mode 100755
index 719760a..b6a3eb1
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/PasswordCredentialHandler.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/PasswordCredentialHandler.java
@@ -1,9 +1,5 @@
package org.keycloak.models.mongo.keycloak.credentials;
-import java.util.Date;
-import java.util.Map;
-import java.util.UUID;
-
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.keycloak.data.UserData;
@@ -12,6 +8,10 @@ import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.encoder.PasswordEncoder;
import org.picketlink.idm.credential.encoder.SHAPasswordEncoder;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
/**
* Defacto forked from {@link org.picketlink.idm.credential.handler.PasswordCredentialHandler}
*
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/TOTPCredentialHandler.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/TOTPCredentialHandler.java
old mode 100644
new mode 100755
index b8f02e7..45a76f7
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/TOTPCredentialHandler.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/credentials/TOTPCredentialHandler.java
@@ -1,8 +1,5 @@
package org.keycloak.models.mongo.keycloak.credentials;
-import java.util.Date;
-import java.util.Map;
-
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.keycloak.data.UserData;
@@ -10,11 +7,11 @@ import org.keycloak.models.mongo.keycloak.data.credentials.OTPData;
import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.util.TimeBasedOTP;
+import java.util.Date;
+import java.util.Map;
+
import static org.picketlink.common.util.StringUtil.isNullOrEmpty;
-import static org.picketlink.idm.credential.util.TimeBasedOTP.DEFAULT_ALGORITHM;
-import static org.picketlink.idm.credential.util.TimeBasedOTP.DEFAULT_DELAY_WINDOW;
-import static org.picketlink.idm.credential.util.TimeBasedOTP.DEFAULT_INTERVAL_SECONDS;
-import static org.picketlink.idm.credential.util.TimeBasedOTP.DEFAULT_NUMBER_DIGITS;
+import static org.picketlink.idm.credential.util.TimeBasedOTP.*;
/**
* Defacto forked from {@link org.picketlink.idm.credential.handler.TOTPCredentialHandler}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/OTPData.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/OTPData.java
old mode 100644
new mode 100755
index 8ab31a6..6983f83
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/OTPData.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/OTPData.java
@@ -1,11 +1,11 @@
package org.keycloak.models.mongo.keycloak.data.credentials;
-import java.util.Date;
-
import org.keycloak.models.mongo.api.AbstractNoSQLObject;
import org.keycloak.models.mongo.api.NoSQLCollection;
import org.keycloak.models.mongo.api.NoSQLField;
+import java.util.Date;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/PasswordData.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/PasswordData.java
old mode 100644
new mode 100755
index 7480e1f..6ac585f
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/PasswordData.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/credentials/PasswordData.java
@@ -1,11 +1,11 @@
package org.keycloak.models.mongo.keycloak.data.credentials;
-import java.util.Date;
-
import org.keycloak.models.mongo.api.AbstractNoSQLObject;
import org.keycloak.models.mongo.api.NoSQLCollection;
import org.keycloak.models.mongo.api.NoSQLField;
+import java.util.Date;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RealmData.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RealmData.java
old mode 100644
new mode 100755
index 5247d60..d9aa0ae
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RealmData.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RealmData.java
@@ -1,7 +1,5 @@
package org.keycloak.models.mongo.keycloak.data;
-import java.util.List;
-
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.NoSQLCollection;
import org.keycloak.models.mongo.api.NoSQLField;
@@ -9,6 +7,8 @@ import org.keycloak.models.mongo.api.NoSQLId;
import org.keycloak.models.mongo.api.NoSQLObject;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RoleData.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RoleData.java
old mode 100644
new mode 100755
index 29bc1f8..9bd14d2
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RoleData.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/RoleData.java
@@ -1,7 +1,5 @@
package org.keycloak.models.mongo.keycloak.data;
-import java.util.List;
-
import org.jboss.logging.Logger;
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.NoSQLCollection;
@@ -10,6 +8,8 @@ import org.keycloak.models.mongo.api.NoSQLId;
import org.keycloak.models.mongo.api.NoSQLObject;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/UserData.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/UserData.java
old mode 100644
new mode 100755
index cfeb67d..c57bca3
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/UserData.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/data/UserData.java
@@ -1,7 +1,5 @@
package org.keycloak.models.mongo.keycloak.data;
-import java.util.List;
-
import org.jboss.logging.Logger;
import org.keycloak.models.UserModel;
import org.keycloak.models.mongo.api.AbstractAttributedNoSQLObject;
@@ -12,6 +10,8 @@ import org.keycloak.models.mongo.api.NoSQLId;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.keycloak.data.credentials.PasswordData;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java
new file mode 100755
index 0000000..87c62af
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java
@@ -0,0 +1,15 @@
+package org.keycloak.models.mongo.keycloak;
+
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ModelProvider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class MongoModelProvider implements ModelProvider {
+ @Override
+ public KeycloakSessionFactory createFactory() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
old mode 100644
new mode 100755
index 8f6b6f8..386ca31
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
@@ -1,10 +1,10 @@
package org.keycloak.models.mongo.test;
-import java.util.List;
-
import org.keycloak.models.mongo.api.AbstractNoSQLObject;
import org.keycloak.models.mongo.api.NoSQLField;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoDBModelTest.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoDBModelTest.java
old mode 100644
new mode 100755
index 262ade8..3b8651a
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoDBModelTest.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoDBModelTest.java
@@ -1,10 +1,5 @@
package org.keycloak.models.mongo.test;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import com.mongodb.DB;
import com.mongodb.MongoClient;
import org.junit.After;
@@ -15,6 +10,11 @@ import org.keycloak.models.mongo.api.NoSQLObject;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.impl.MongoDBImpl;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
old mode 100644
new mode 100755
index ab2ded3..7f8d0d9
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
@@ -1,12 +1,12 @@
package org.keycloak.models.mongo.test;
-import java.util.List;
-
import org.keycloak.models.mongo.api.AbstractNoSQLObject;
import org.keycloak.models.mongo.api.NoSQLCollection;
import org.keycloak.models.mongo.api.NoSQLField;
import org.keycloak.models.mongo.api.NoSQLId;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmData.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmData.java
index 24e1f03..06e0736 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmData.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmData.java
@@ -3,8 +3,7 @@ package org.keycloak.models.picketlink.mappings;
import org.picketlink.idm.model.AbstractPartition;
import org.picketlink.idm.model.annotation.AttributeProperty;
-import java.io.Serializable;
-import java.util.HashMap;
+import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -26,8 +25,8 @@ public class RealmData extends AbstractPartition {
private String publicKeyPem;
private String privateKeyPem;
private String[] defaultRoles;
- private HashMap<String, String> smtpConfig;
- private HashMap<String, String> socialConfig;
+ private Map<String, String> smtpConfig;
+ private Map<String, String> socialConfig;
public RealmData() {
super(null);
@@ -170,20 +169,20 @@ public class RealmData extends AbstractPartition {
}
@AttributeProperty
- public HashMap<String, String> getSmtpConfig() {
+ public Map<String, String> getSmtpConfig() {
return smtpConfig;
}
- public void setSmtpConfig(HashMap<String, String> smtpConfig) {
+ public void setSmtpConfig(Map<String, String> smtpConfig) {
this.smtpConfig = smtpConfig;
}
@AttributeProperty
- public HashMap<String, String> getSocialConfig() {
+ public Map<String, String> getSocialConfig() {
return socialConfig;
}
- public void setSocialConfig(HashMap<String, String> socialConfig) {
+ public void setSocialConfig(Map<String, String> socialConfig) {
this.socialConfig = socialConfig;
}
}
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmEntity.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmEntity.java
index 74a3f09..4be31e6 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmEntity.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/RealmEntity.java
@@ -5,7 +5,11 @@ import org.picketlink.idm.jpa.annotations.OwnerReference;
import org.picketlink.idm.jpa.annotations.entity.IdentityManaged;
import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
-import javax.persistence.*;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.OneToOne;
import java.io.Serializable;
import java.util.HashMap;
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/OAuthClientAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/OAuthClientAdapter.java
index 310b4ce..474a0b5 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/OAuthClientAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/OAuthClientAdapter.java
@@ -31,14 +31,4 @@ public class OAuthClientAdapter implements OAuthClientModel {
return new UserAdapter(delegate.getOauthAgent(), idm);
}
- @Override
- public String getBaseUrl() {
- return delegate.getBaseUrl();
- }
-
- @Override
- public void setBaseUrl(String base) {
- delegate.setBaseUrl(base);
- relationshipManager.update(delegate);
- }
}
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkKeycloakSession.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkKeycloakSession.java
index 7d17339..fcaf72e 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkKeycloakSession.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkKeycloakSession.java
@@ -5,7 +5,6 @@ import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.picketlink.mappings.RealmData;
-import org.keycloak.models.picketlink.relationships.RealmAdminRelationship;
import org.keycloak.models.picketlink.relationships.RealmListingRelationship;
import org.keycloak.models.utils.KeycloakSessionUtils;
import org.picketlink.idm.PartitionManager;
@@ -15,7 +14,6 @@ import org.picketlink.idm.query.RelationshipQuery;
import javax.persistence.EntityManager;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkModelProvider.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkModelProvider.java
new file mode 100755
index 0000000..67f4d7a
--- /dev/null
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/PicketlinkModelProvider.java
@@ -0,0 +1,77 @@
+package org.keycloak.models.picketlink;
+
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ModelProvider;
+import org.keycloak.models.picketlink.mappings.ApplicationEntity;
+import org.keycloak.models.picketlink.mappings.RealmEntity;
+import org.picketlink.idm.PartitionManager;
+import org.picketlink.idm.config.IdentityConfigurationBuilder;
+import org.picketlink.idm.internal.DefaultPartitionManager;
+import org.picketlink.idm.jpa.internal.JPAContextInitializer;
+import org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity;
+import org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PicketlinkModelProvider implements ModelProvider {
+ @Override
+ public KeycloakSessionFactory createFactory() {
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("picketlink-keycloak-identity-store");
+ return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
+ }
+
+ public static PartitionManager buildPartitionManager() {
+ IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
+
+ builder
+ .named("KEYCLOAK_JPA_CONFIG")
+ .stores()
+ .jpa()
+ .mappedEntity(
+ AttributedTypeEntity.class,
+ AccountTypeEntity.class,
+ RoleTypeEntity.class,
+ GroupTypeEntity.class,
+ IdentityTypeEntity.class,
+ RelationshipTypeEntity.class,
+ RelationshipIdentityTypeEntity.class,
+ PartitionTypeEntity.class,
+ PasswordCredentialTypeEntity.class,
+ DigestCredentialTypeEntity.class,
+ X509CredentialTypeEntity.class,
+ OTPCredentialTypeEntity.class,
+ AttributeTypeEntity.class,
+ RealmEntity.class,
+ ApplicationEntity.class
+ )
+ .supportGlobalRelationship(org.picketlink.idm.model.Relationship.class)
+ .addContextInitializer(new JPAContextInitializer(null) {
+ @Override
+ public EntityManager getEntityManager() {
+ return PicketlinkKeycloakSession.currentEntityManager.get();
+ }
+ })
+ .supportAllFeatures();
+
+ DefaultPartitionManager partitionManager = new DefaultPartitionManager(builder.buildAll());
+ return partitionManager;
+ }
+
+}
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
index 58c44b4..3279abf 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
@@ -2,11 +2,25 @@ package org.keycloak.models.picketlink;
import org.bouncycastle.openssl.PEMWriter;
import org.keycloak.PemUtils;
-import org.keycloak.models.*;
-import org.keycloak.models.picketlink.mappings.RealmData;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.IdGenerator;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
import org.keycloak.models.picketlink.mappings.ApplicationData;
-import org.keycloak.models.picketlink.relationships.*;
+import org.keycloak.models.picketlink.mappings.RealmData;
+import org.keycloak.models.picketlink.relationships.ApplicationRelationship;
+import org.keycloak.models.picketlink.relationships.OAuthClientRelationship;
+import org.keycloak.models.picketlink.relationships.OAuthClientRequiredCredentialRelationship;
import org.keycloak.models.picketlink.relationships.RequiredApplicationCredentialRelationship;
+import org.keycloak.models.picketlink.relationships.RequiredCredentialRelationship;
+import org.keycloak.models.picketlink.relationships.ScopeRelationship;
+import org.keycloak.models.picketlink.relationships.SocialLinkRelationship;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.RelationshipManager;
@@ -595,7 +609,6 @@ public class RealmAdapter implements RealmModel {
idm.add(resourceUser);
applicationData.setResourceUser(resourceUser);
applicationData.setResourceName(name);
- applicationData.setResourceUser(resourceUser);
partitionManager.add(applicationData);
ApplicationRelationship resourceRelationship = new ApplicationRelationship();
resourceRelationship.setRealm(realm.getName());
@@ -749,12 +762,14 @@ public class RealmAdapter implements RealmModel {
@Override
public List<String> getDefaultRoles() {
- if (realm.getDefaultRoles() != null) {
- return Arrays.asList(realm.getDefaultRoles());
- }
- else {
- return Collections.emptyList();
+ if (realm.getDefaultRoles() == null) return Collections.emptyList();
+ List<String> list = new ArrayList<String>();
+ for (String role : realm.getDefaultRoles()) {
+ RoleModel model = getRole(role);
+ if (model == null) throw new RuntimeException("default role missing");
+ list.add(role);
}
+ return list;
}
@Override
@@ -865,23 +880,23 @@ public class RealmAdapter implements RealmModel {
}
@Override
- public HashMap<String, String> getSmtpConfig() {
+ public Map<String, String> getSmtpConfig() {
return realm.getSmtpConfig();
}
@Override
- public void setSmtpConfig(HashMap<String, String> smtpConfig) {
+ public void setSmtpConfig(Map<String, String> smtpConfig) {
realm.setSmtpConfig(smtpConfig);
updateRealm();
}
@Override
- public HashMap<String, String> getSocialConfig() {
+ public Map<String, String> getSocialConfig() {
return realm.getSocialConfig();
}
@Override
- public void setSocialConfig(HashMap<String, String> socialConfig) {
+ public void setSocialConfig(Map<String, String> socialConfig) {
realm.setSocialConfig(socialConfig);
updateRealm();
}
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/relationships/RealmListingRelationship.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/relationships/RealmListingRelationship.java
index 26636e6..bb4856a 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/relationships/RealmListingRelationship.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/relationships/RealmListingRelationship.java
@@ -3,9 +3,7 @@ package org.keycloak.models.picketlink.relationships;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
-import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter;
-import org.picketlink.idm.query.RelationshipQueryParameter;
/**
* Picketlink doesn't allow you to query for all partitions, thus this stupid relationship...
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
index e44c92a..2555f74 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
@@ -1,17 +1,16 @@
package org.keycloak.models.picketlink;
+import org.keycloak.models.UserModel;
+import org.picketlink.idm.IdentityManager;
+import org.picketlink.idm.model.Attribute;
+import org.picketlink.idm.model.sample.User;
+
import java.io.Serializable;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import org.keycloak.models.UserModel;
-import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.model.Attribute;
-import org.picketlink.idm.model.sample.User;
-
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
model/pom.xml 2(+1 -1)
diff --git a/model/pom.xml b/model/pom.xml
index 7e2fca5..26992ca 100755
--- a/model/pom.xml
+++ b/model/pom.xml
@@ -37,6 +37,6 @@
<module>api</module>
<module>picketlink</module>
<module>jpa</module>
- <!--<module>mongo</module>-->
+ <!-- <module>mongo</module> -->
</modules>
</project>
pom.xml 4(+2 -2)
diff --git a/pom.xml b/pom.xml
index c050cc9..7351a4c 100755
--- a/pom.xml
+++ b/pom.xml
@@ -9,8 +9,8 @@
<packaging>pom</packaging>
<properties>
- <resteasy.version>3.0.4.Final</resteasy.version>
- <undertow.version>1.0.0.Beta12</undertow.version>
+ <resteasy.version>3.0.5.Final</resteasy.version>
+ <undertow.version>1.0.0.Beta21</undertow.version>
<picketlink.version>2.5.0.Beta6</picketlink.version>
<mongo.driver.version>2.11.2</mongo.driver.version>
<jboss.logging.version>3.1.1.GA</jboss.logging.version>
services/pom.xml 6(+6 -0)
diff --git a/services/pom.xml b/services/pom.xml
index 52d2ab8..1df957c 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -33,6 +33,12 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-picketlink</artifactId>
<version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-model-jpa</artifactId>
+ <version>${project.version}</version>
</dependency>
<!--<dependency>
diff --git a/services/src/main/java/org/keycloak/services/email/EmailSender.java b/services/src/main/java/org/keycloak/services/email/EmailSender.java
index 960410c..185ca83 100755
--- a/services/src/main/java/org/keycloak/services/email/EmailSender.java
+++ b/services/src/main/java/org/keycloak/services/email/EmailSender.java
@@ -21,28 +21,25 @@
*/
package org.keycloak.services.email;
-import java.net.URI;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
+import org.jboss.resteasy.logging.Logger;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.AccessCodeEntry;
+import org.keycloak.services.resources.flows.Urls;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
-import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-
-import org.jboss.resteasy.logging.Logger;
-import org.keycloak.services.managers.AccessCodeEntry;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.services.resources.AccountService;
-import org.keycloak.services.resources.flows.Urls;
+import java.net.URI;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
index d662661..cb2bc5a 100755
--- a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
+++ b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
@@ -5,7 +5,12 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakTransaction;
-import javax.servlet.*;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import java.io.IOException;
/**
diff --git a/services/src/main/java/org/keycloak/services/FormService.java b/services/src/main/java/org/keycloak/services/FormService.java
index 210fad6..9a357a3 100755
--- a/services/src/main/java/org/keycloak/services/FormService.java
+++ b/services/src/main/java/org/keycloak/services/FormService.java
@@ -21,21 +21,20 @@
*/
package org.keycloak.services;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.imageio.spi.ServiceRegistry;
-import javax.ws.rs.core.MultivaluedMap;
-
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.resources.flows.FormFlows;
import org.keycloak.social.SocialProvider;
+import javax.imageio.spi.ServiceRegistry;
+import javax.ws.rs.core.MultivaluedMap;
+import java.net.URI;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
/**
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
*/
@@ -95,7 +94,7 @@ public interface FormService {
this.message = message;
socialProviders = new LinkedList<SocialProvider>();
- HashMap<String, String> socialConfig = realm.getSocialConfig();
+ Map<String, String> socialConfig = realm.getSocialConfig();
if (socialConfig != null) {
for (Iterator<SocialProvider> itr = ServiceRegistry.lookupProviders(org.keycloak.social.SocialProvider.class); itr.hasNext(); ) {
SocialProvider p = itr.next();
diff --git a/services/src/main/java/org/keycloak/services/listeners/MongoRunnerListener.java b/services/src/main/java/org/keycloak/services/listeners/MongoRunnerListener.java
old mode 100644
new mode 100755
index f0df0a6..a1f6788
--- a/services/src/main/java/org/keycloak/services/listeners/MongoRunnerListener.java
+++ b/services/src/main/java/org/keycloak/services/listeners/MongoRunnerListener.java
@@ -1,8 +1,5 @@
package org.keycloak.services.listeners;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
@@ -12,6 +9,9 @@ import de.flapdoodle.embed.process.runtime.Network;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.services.utils.PropertiesManager;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
index 9dceed8..07bebe3 100755
--- a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
+++ b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
@@ -1,10 +1,10 @@
package org.keycloak.services.managers;
import org.keycloak.models.RealmModel;
-import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.representations.SkeletonKeyToken;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 9d36f8f..3754164 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -1,6 +1,12 @@
package org.keycloak.services.managers;
-import org.keycloak.models.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import java.util.UUID;
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index fc854a3..67a8286 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -1,14 +1,23 @@
package org.keycloak.services.managers;
+import org.jboss.resteasy.logging.Logger;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.UserRoleMappingRepresentation;
+
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
-import org.keycloak.representations.idm.*;
-
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -69,12 +78,15 @@ public class ApplicationManager {
if (resourceRep.getRoleMappings() != null) {
for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
UserModel user = realm.getUser(mapping.getUsername());
+ if (user == null) {
+ throw new RuntimeException("User not found");
+ }
for (String roleString : mapping.getRoles()) {
RoleModel role = applicationModel.getRole(roleString.trim());
if (role == null) {
role = applicationModel.addRole(roleString.trim());
}
- realm.grantRole(user, role);
+ applicationModel.grantRole(user, role);
}
}
}
@@ -142,7 +154,7 @@ public class ApplicationManager {
}
if (!applicationModel.getDefaultRoles().isEmpty()) {
- rep.setDefaultRoles((String[]) applicationModel.getDefaultRoles().toArray());
+ rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
}
return rep;
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index bc50831..a3434b3 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -8,17 +8,21 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.RSATokenVerifier;
import org.keycloak.VerificationException;
import org.keycloak.models.Constants;
-import org.keycloak.representations.SkeletonKeyToken;
-import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.SaasService;
import javax.ws.rs.NotAuthorizedException;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
diff --git a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
index 0b10d61..7840566 100755
--- a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
@@ -26,19 +26,16 @@ public class OAuthClientManager {
public OAuthClientModel create(OAuthClientRepresentation rep) {
OAuthClientModel model = create(rep.getName());
- model.setBaseUrl(rep.getBaseUrl());
model.getOAuthAgent().setEnabled(rep.isEnabled());
return model;
}
public void update(OAuthClientRepresentation rep, OAuthClientModel model) {
- model.setBaseUrl(rep.getBaseUrl());
}
public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
OAuthClientRepresentation rep = new OAuthClientRepresentation();
rep.setId(model.getId());
- rep.setBaseUrl(model.getBaseUrl());
rep.setName(model.getOAuthAgent().getLoginName());
rep.setEnabled(model.getOAuthAgent().isEnabled());
return rep;
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 017a08c..8cd43a0 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -1,14 +1,36 @@
package org.keycloak.services.managers;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
-import org.keycloak.representations.idm.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.SocialLinkRepresentation;
+import org.keycloak.representations.idm.SocialMappingRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserRoleMappingRepresentation;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/**
@@ -88,7 +110,7 @@ public class RealmManager {
realm.updateRequiredApplicationCredentials(rep.getRequiredApplicationCredentials());
}
if (rep.getDefaultRoles() != null) {
- realm.updateDefaultRoles(rep.getDefaultRoles());
+ realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
}
if (rep.getAccountManagement() != null && rep.getAccountManagement()) {
@@ -431,7 +453,9 @@ public class RealmManager {
List<String> defaultRoles = realm.getDefaultRoles();
if (!defaultRoles.isEmpty()) {
- rep.setDefaultRoles((String[]) realm.getDefaultRoles().toArray());
+ List<String> roleStrings = new ArrayList<String>();
+ roleStrings.addAll(defaultRoles);
+ rep.setDefaultRoles(roleStrings);
}
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index 5425cd8..cee3047 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -4,9 +4,9 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.TokenIdGenerator;
-import org.keycloak.representations.idm.admin.LogoutAction;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.admin.LogoutAction;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index e7cb2ff..1fe7768 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -4,14 +4,21 @@ import org.jboss.resteasy.jose.Base64Url;
import org.jboss.resteasy.jose.jws.JWSBuilder;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken;
import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.util.*;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -45,7 +52,6 @@ public class TokenManager {
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
Set<String> realmMapping = realm.getRoleMappingValues(user);
- realmMapping.addAll(realm.getDefaultRoles());
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
Set<String> scope = realm.getScopeMappingValues(client);
@@ -69,8 +75,6 @@ public class TokenManager {
}
for (ApplicationModel resource : realm.getApplications()) {
Set<String> mapping = resource.getRoleMappingValues(user);
- mapping.addAll(resource.getDefaultRoles());
-
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
Set<String> scope = resource.getScopeMappingValues(client);
if (scope.size() > 0) {
@@ -188,7 +192,6 @@ public class TokenManager {
}
Set<String> realmMapping = realm.getRoleMappingValues(user);
- realmMapping.addAll(realm.getDefaultRoles());
if (realmMapping != null && realmMapping.size() > 0) {
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
@@ -200,8 +203,6 @@ public class TokenManager {
if (resources != null) {
for (ApplicationModel resource : resources) {
Set<String> mapping = resource.getRoleMappingValues(user);
- mapping.addAll(resource.getDefaultRoles());
-
if (mapping == null) continue;
SkeletonKeyToken.Access access = token.addAccess(resource.getName())
.verifyCaller(resource.isSurrogateAuthRequired());
diff --git a/services/src/main/java/org/keycloak/services/managers/UserManager.java b/services/src/main/java/org/keycloak/services/managers/UserManager.java
index 4d7a7ec..1ce544a 100755
--- a/services/src/main/java/org/keycloak/services/managers/UserManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/UserManager.java
@@ -1,10 +1,10 @@
package org.keycloak.services.managers;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import java.util.Map;
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 799b101..584ef1c 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -28,6 +28,7 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.AbstractOAuthClient;
import org.keycloak.jaxrs.JaxrsOAuthClient;
import org.keycloak.models.*;
+import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.AccessCodeEntry;
@@ -40,7 +41,6 @@ import org.keycloak.services.resources.flows.FormFlows;
import org.keycloak.services.resources.flows.Pages;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.services.validation.Validation;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@@ -373,7 +373,8 @@ public class AccountService {
UserModel client = auth.getClient();
if (realm.hasRole(client, Constants.APPLICATION_ROLE)) {
// Tokens from cookies don't have roles
- if (hasRole(client, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(client, role))) {
+ UserModel user = auth.getUser();
+ if (hasRole(user, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(user, role))) {
return true;
}
}
@@ -389,9 +390,6 @@ public class AccountService {
}
private boolean hasRole(UserModel user, String role) {
- if (application.getDefaultRoles().contains(role)) {
- return true;
- }
return application.hasRole(user, role);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index 9177495..7a1e229 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -2,17 +2,24 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
-import org.keycloak.representations.idm.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
-import javax.ws.rs.core.Context;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.util.*;
+import java.util.List;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
index 40e3ca7..29cc957 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
@@ -2,15 +2,20 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.representations.idm.ApplicationRepresentation;
-import org.keycloak.services.managers.ApplicationManager;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.services.managers.ApplicationManager;
+import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
index f588ab2..f7a2286 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
@@ -2,15 +2,20 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
-import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.OAuthClientRepresentation;
-import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.List;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
index 2873767..408a48f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
@@ -2,18 +2,19 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.OAuthClientRepresentation;
-import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.OAuthClientManager;
-import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
-import javax.ws.rs.container.ResourceContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 8b552d8..ec4ae9b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -2,18 +2,19 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.util.ArrayList;
-import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index c7e0262..fb4bfeb 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -2,16 +2,27 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.SaasService;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import javax.ws.rs.container.ResourceContext;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index 0c02a78..c0c0a5f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -5,7 +5,15 @@ import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RoleRepresentation;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index d093e16..f3f91ef 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -1,13 +1,24 @@
package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
-import org.keycloak.models.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 600c2ad..029d4c9 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -2,11 +2,30 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.models.*;
-import org.keycloak.representations.idm.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.MappingsRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
diff --git a/services/src/main/java/org/keycloak/services/resources/Cors.java b/services/src/main/java/org/keycloak/services/resources/Cors.java
old mode 100644
new mode 100755
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
index c8711ea..41aa04f 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
@@ -22,9 +22,9 @@
package org.keycloak.services.resources.flows;
import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.TokenManager;
-import org.keycloak.models.RealmModel;
import javax.ws.rs.core.UriInfo;
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java
index 68df5a9..3dcd6b5 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java
@@ -21,21 +21,16 @@
*/
package org.keycloak.services.resources.flows;
-import java.net.URI;
-import java.util.Iterator;
-import java.util.List;
-
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.ResteasyUriInfo;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.services.FormService;
import org.keycloak.services.email.EmailSender;
import org.keycloak.services.managers.AccessCodeEntry;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.services.messages.Messages;
-import org.picketlink.idm.model.sample.Realm;
import javax.imageio.spi.ServiceRegistry;
import javax.ws.rs.core.MediaType;
@@ -43,6 +38,9 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+import java.util.Iterator;
+import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -51,7 +49,6 @@ public class FormFlows {
public static final String DATA = "KEYCLOAK_FORMS_DATA";
public static final String ERROR_MESSAGE = "KEYCLOAK_FORMS_ERROR_MESSAGE";
- public static final String REALM = Realm.class.getName();
public static final String USER = UserModel.class.getName();
public static final String SOCIAL_REGISTRATION = "socialRegistration";
public static final String CODE = "code";
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
index cc12de2..b178df9 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
@@ -21,24 +21,23 @@
*/
package org.keycloak.services.resources.flows;
-import java.util.HashSet;
-import java.util.Set;
-
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.models.Constants;
-import org.keycloak.services.managers.AccessCodeEntry;
-import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.TokenManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.AccessCodeEntry;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+import java.util.HashSet;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -68,7 +67,8 @@ public class OAuthFlows {
}
public Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect) {
- Set<String> redirectUris = accessCode.getClient().getRedirectUris();
+ UserModel client = realm.getUser(accessCode.getClient().getLoginName());
+ Set<String> redirectUris = client.getRedirectUris();
if (!redirectUris.isEmpty() && !redirectUris.contains(redirect)) {
return forwardToSecurityFailure("Invalid redirect_uri " + redirect);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
index b9f457a..a2061aa 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
@@ -21,7 +21,12 @@
*/
package org.keycloak.services.resources.flows;
-import org.keycloak.services.resources.*;
+import org.keycloak.services.resources.AccountService;
+import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.services.resources.RequiredActionsService;
+import org.keycloak.services.resources.SaasService;
+import org.keycloak.services.resources.SocialResource;
+import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 96e922d..867c2c1 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -1,28 +1,16 @@
package org.keycloak.services.resources;
import org.keycloak.SkeletonKeyContextResolver;
-import org.keycloak.services.managers.TokenManager;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.picketlink.PicketlinkKeycloakSession;
-import org.keycloak.models.picketlink.PicketlinkKeycloakSessionFactory;
-import org.keycloak.models.picketlink.mappings.ApplicationEntity;
-import org.keycloak.models.picketlink.mappings.RealmEntity;
-import org.keycloak.services.utils.PropertiesManager;
+import org.keycloak.models.ModelProvider;
import org.keycloak.services.managers.SocialRequestManager;
-import org.picketlink.idm.PartitionManager;
-import org.picketlink.idm.config.IdentityConfigurationBuilder;
-import org.picketlink.idm.internal.DefaultPartitionManager;
-import org.picketlink.idm.jpa.internal.JPAContextInitializer;
-import org.picketlink.idm.jpa.model.sample.simple.*;
+import org.keycloak.services.managers.TokenManager;
+import org.keycloak.services.utils.PropertiesManager;
import javax.annotation.PreDestroy;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.Persistence;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
-
import java.lang.reflect.Constructor;
import java.util.HashSet;
import java.util.Set;
@@ -62,14 +50,32 @@ public class KeycloakApplication extends Application {
return buildMongoDBSessionFactory();
} else if (PropertiesManager.isPicketlinkSessionFactory()) {
return buildPicketlinkSessionFactory();
+ } else if (PropertiesManager.isJpaSessionFactory()) {
+ return buildJpaSessionFactory();
} else {
throw new IllegalStateException("Unknown session factory type: " + PropertiesManager.getSessionFactoryType());
}
}
+ private static KeycloakSessionFactory buildJpaSessionFactory() {
+ ModelProvider provider = null;
+ try {
+ provider = (ModelProvider)Class.forName("org.keycloak.models.jpa.JpaModelProvider").newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return provider.createFactory();
+ }
+
+
private static KeycloakSessionFactory buildPicketlinkSessionFactory() {
- EntityManagerFactory emf = Persistence.createEntityManagerFactory("keycloak-identity-store");
- return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
+ ModelProvider provider = null;
+ try {
+ provider = (ModelProvider)Class.forName("org.keycloak.models.picketlink.PicketlinkModelProvider").newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return provider.createFactory();
}
private static KeycloakSessionFactory buildMongoDBSessionFactory() {
@@ -97,46 +103,7 @@ public class KeycloakApplication extends Application {
factory.close();
}
- public PartitionManager createPartitionManager() {
- return buildPartitionManager();
- }
- public static PartitionManager buildPartitionManager() {
- IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
-
- builder
- .named("KEYCLOAK_JPA_CONFIG")
- .stores()
- .jpa()
- .mappedEntity(
- AttributedTypeEntity.class,
- AccountTypeEntity.class,
- RoleTypeEntity.class,
- GroupTypeEntity.class,
- IdentityTypeEntity.class,
- RelationshipTypeEntity.class,
- RelationshipIdentityTypeEntity.class,
- PartitionTypeEntity.class,
- PasswordCredentialTypeEntity.class,
- DigestCredentialTypeEntity.class,
- X509CredentialTypeEntity.class,
- OTPCredentialTypeEntity.class,
- AttributeTypeEntity.class,
- RealmEntity.class,
- ApplicationEntity.class
- )
- .supportGlobalRelationship(org.picketlink.idm.model.Relationship.class)
- .addContextInitializer(new JPAContextInitializer(null) {
- @Override
- public EntityManager getEntityManager() {
- return PicketlinkKeycloakSession.currentEntityManager.get();
- }
- })
- .supportAllFeatures();
-
- DefaultPartitionManager partitionManager = new DefaultPartitionManager(builder.buildAll());
- return partitionManager;
- }
@Override
diff --git a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
index 03b7d5f..01094b4 100755
--- a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
@@ -2,8 +2,8 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.PublishedRealmRepresentation;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
diff --git a/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java b/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
old mode 100644
new mode 100755
index 9d02111..3ae4b67
--- a/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
@@ -7,7 +7,11 @@ import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import javax.servlet.ServletException;
-import javax.ws.rs.*;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 0e1bc0f..f96f343 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -3,10 +3,10 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.managers.TokenManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.managers.TokenManager;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
diff --git a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
index 40f0ed8..3199c01 100755
--- a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
@@ -29,6 +29,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.email.EmailSender;
import org.keycloak.services.managers.AccessCodeEntry;
@@ -38,13 +39,17 @@ import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.FormFlows;
import org.keycloak.services.validation.Validation;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
import java.util.HashSet;
import java.util.Set;
diff --git a/services/src/main/java/org/keycloak/services/resources/SaasService.java b/services/src/main/java/org/keycloak/services/resources/SaasService.java
index 534307c..ef936df 100755
--- a/services/src/main/java/org/keycloak/services/resources/SaasService.java
+++ b/services/src/main/java/org/keycloak/services/resources/SaasService.java
@@ -9,8 +9,12 @@ import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotImplementedYetException;
import org.keycloak.AbstractOAuthClient;
import org.keycloak.jaxrs.JaxrsOAuthClient;
-import org.keycloak.models.*;
-import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AccessCodeEntry;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
@@ -21,13 +25,27 @@ import org.keycloak.services.resources.admin.RealmsAdminResource;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows;
-import javax.ws.rs.*;
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ResourceContext;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -246,6 +264,7 @@ public class SaasService {
@GET
@NoCache
public Response loginPage() {
+ logger.debug("loginPage ********************** <---");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
authManager.expireSaasIdentityCookie(uriInfo);
@@ -271,7 +290,7 @@ public class SaasService {
) {
try {
- logger.debug("loginRedirect ********************** <---");
+ logger.info("loginRedirect ********************** <---");
if (error != null) {
logger.debug("error from oauth");
throw new ForbiddenException("error");
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
index 573da77..908844c 100755
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
@@ -21,37 +21,15 @@
*/
package org.keycloak.services.resources;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-
-import javax.imageio.spi.ServiceRegistry;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.container.ResourceContext;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Cookie;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.NewCookie;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriInfo;
-
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
-import org.keycloak.models.*;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
@@ -68,6 +46,31 @@ import org.keycloak.social.SocialProviderException;
import org.keycloak.services.managers.SocialRequestManager;
import org.keycloak.social.SocialUser;
+import javax.imageio.spi.ServiceRegistry;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.container.ResourceContext;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -170,6 +173,7 @@ public class SocialResource {
// already registered. But actually Keycloak allows duplicate emails
} else {
user = realm.addUser(socialUser.getUsername());
+ user.setEnabled(true);
user.setFirstName(socialUser.getFirstName());
user.setLastName(socialUser.getLastName());
user.setEmail(socialUser.getEmail());
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index c825004..580473b 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -8,7 +8,16 @@ import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
-import org.keycloak.models.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -18,7 +27,6 @@ import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.messages.Messages;
-import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.validation.Validation;
@@ -40,9 +48,11 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
-
import java.security.PrivateKey;
-import java.util.*;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -262,18 +272,22 @@ public class TokenService {
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) {
+ logger.warn("Realm not enabled");
return oauth.forwardToSecurityFailure("Realm not enabled");
}
UserModel client = realm.getUser(clientId);
if (client == null) {
+ logger.warn("Unknown login requester.");
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
+ logger.warn("Login requester not enabled.");
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
if (!realm.isRegistrationAllowed()) {
+ logger.warn("Registration not allowed");
return oauth.forwardToSecurityFailure("Registration not allowed");
}
@@ -297,6 +311,7 @@ public class TokenService {
}
user = realm.addUser(username);
+ user.setEnabled(true);
user.setFirstName(formData.getFirst("firstName"));
user.setLastName(formData.getFirst("lastName"));
@@ -309,6 +324,17 @@ public class TokenService {
realm.updateCredential(user, credentials);
}
+ for (String r : realm.getDefaultRoles()) {
+ realm.grantRole(user, realm.getRole(r));
+ }
+
+ for (ApplicationModel application : realm.getApplications()) {
+ for (String r : application.getDefaultRoles()) {
+ application.grantRole(user, application.getRole(r));
+ }
+ }
+
+
return null;
}
@@ -409,7 +435,7 @@ public class TokenService {
logger.debug("accessRequest SUCCESS");
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
- return Cors.add(request, Response.ok(res)).allowedOrigins(client).build();
+ return Cors.add(request, Response.ok(res)).allowedOrigins(client).allowedMethods("POST").build();
}
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
@@ -440,36 +466,41 @@ public class TokenService {
public Response loginPage(final @QueryParam("response_type") String responseType,
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state, final @QueryParam("prompt") String prompt) {
+ logger.info("TokenService.loginPage");
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) {
+ logger.warn("Realm not enabled");
oauth.forwardToSecurityFailure("Realm not enabled");
return null;
}
UserModel client = realm.getUser(clientId);
if (client == null) {
+ logger.warn("Unknown login requester: " + clientId);
oauth.forwardToSecurityFailure("Unknown login requester.");
transaction.rollback();
return null;
}
if (!client.isEnabled()) {
+ logger.warn("Login requester not enabled.");
oauth.forwardToSecurityFailure("Login requester not enabled.");
transaction.rollback();
session.close();
return null;
}
-
+ logger.info("Checking roles...");
RoleModel resourceRole = realm.getRole(Constants.APPLICATION_ROLE);
RoleModel identityRequestRole = realm.getRole(Constants.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
+ logger.warn("Login requester not allowed to request login.");
oauth.forwardToSecurityFailure("Login requester not allowed to request login.");
transaction.rollback();
session.close();
return null;
}
-
+ logger.info("Checking cookie...");
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) {
logger.debug(user.getLoginName() + " already logged in.");
@@ -479,7 +510,7 @@ public class TokenService {
if (prompt != null && prompt.equals("none")) {
return oauth.redirectError(client, "access_denied", state, redirect);
}
-
+ logger.info("forwardToLogin() now...");
return Flows.forms(realm, request, uriInfo).forwardToLogin();
}
@@ -488,21 +519,26 @@ public class TokenService {
public Response registerPage(final @QueryParam("response_type") String responseType,
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
+ logger.info("**********registerPage()");
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) {
+ logger.warn("Realm not enabled");
return oauth.forwardToSecurityFailure("Realm not enabled");
}
UserModel client = realm.getUser(clientId);
if (client == null) {
+ logger.warn("Unknown login requester.");
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
+ logger.warn("Login requester not enabled.");
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
if (!realm.isRegistrationAllowed()) {
+ logger.warn("Registration not allowed");
return oauth.forwardToSecurityFailure("Registration not allowed");
}
diff --git a/services/src/main/java/org/keycloak/services/utils/PropertiesManager.java b/services/src/main/java/org/keycloak/services/utils/PropertiesManager.java
old mode 100644
new mode 100755
index ee16547..583a8c8
--- a/services/src/main/java/org/keycloak/services/utils/PropertiesManager.java
+++ b/services/src/main/java/org/keycloak/services/utils/PropertiesManager.java
@@ -8,6 +8,7 @@ public class PropertiesManager {
private static final String SESSION_FACTORY = "keycloak.sessionFactory";
public static final String SESSION_FACTORY_PICKETLINK = "picketlink";
public static final String SESSION_FACTORY_MONGO = "mongo";
+ public static final String SESSION_FACTORY_JPA = "jpa";
private static final String MONGO_HOST = "keycloak.mongodb.host";
private static final String MONGO_PORT = "keycloak.mongodb.port";
@@ -25,7 +26,7 @@ public class PropertiesManager {
public static final int MONGO_DEFAULT_PORT_UNIT_TESTS = 27777;
public static String getSessionFactoryType() {
- return System.getProperty(SESSION_FACTORY, SESSION_FACTORY_PICKETLINK);
+ return System.getProperty(SESSION_FACTORY, SESSION_FACTORY_JPA);
}
public static void setSessionFactoryType(String sessionFactoryType) {
@@ -33,7 +34,7 @@ public class PropertiesManager {
}
public static void setDefaultSessionFactoryType() {
- System.setProperty(SESSION_FACTORY, SESSION_FACTORY_PICKETLINK);
+ System.setProperty(SESSION_FACTORY, SESSION_FACTORY_JPA);
}
public static boolean isMongoSessionFactory() {
@@ -44,6 +45,11 @@ public class PropertiesManager {
return getSessionFactoryType().equals(SESSION_FACTORY_PICKETLINK);
}
+ public static boolean isJpaSessionFactory() {
+ return getSessionFactoryType().equals(SESSION_FACTORY_JPA);
+ }
+
+
public static String getMongoHost() {
return System.getProperty(MONGO_HOST, "localhost");
}
diff --git a/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java b/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
old mode 100644
new mode 100755
index 70a9456..e749f16
--- a/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
+++ b/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
@@ -1,21 +1,19 @@
package org.keycloak.services.email;
-import java.io.IOException;
-import java.lang.Thread.UncaughtExceptionHandler;
-import java.net.SocketException;
-import java.util.HashMap;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.MimeMessage;
-
+import com.icegreen.greenmail.util.GreenMail;
+import com.icegreen.greenmail.util.ServerSetup;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import com.icegreen.greenmail.util.GreenMail;
-import com.icegreen.greenmail.util.ServerSetup;
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.MimeMessage;
+import java.io.IOException;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.net.SocketException;
+import java.util.HashMap;
public class EmailSenderTest {
diff --git a/services/src/test/java/org/keycloak/services/managers/AuthenticationManagerTest.java b/services/src/test/java/org/keycloak/services/managers/AuthenticationManagerTest.java
index a2049fd..4d67838 100755
--- a/services/src/test/java/org/keycloak/services/managers/AuthenticationManagerTest.java
+++ b/services/src/test/java/org/keycloak/services/managers/AuthenticationManagerTest.java
@@ -1,26 +1,21 @@
package org.keycloak.services.managers;
-import java.util.UUID;
-
-import javax.ws.rs.core.MultivaluedHashMap;
-import javax.ws.rs.core.MultivaluedMap;
-
-import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
-import org.keycloak.services.resources.KeycloakApplication;
+import org.keycloak.models.utils.TimeBasedOTP;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
import org.keycloak.test.common.AbstractKeycloakTest;
import org.keycloak.test.common.SessionFactoryTestContext;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.UUID;
public class AuthenticationManagerTest extends AbstractKeycloakTest {
@@ -144,6 +139,7 @@ public class AuthenticationManagerTest extends AbstractKeycloakTest {
am = new AuthenticationManager();
user = realm.addUser("test");
+ user.setEnabled(true);
UserCredentialModel credential = new UserCredentialModel();
credential.setType(CredentialRepresentation.PASSWORD);
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index d6b178a..1c86dfe 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -4,16 +4,20 @@ import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
-import org.keycloak.models.*;
+import org.keycloak.models.Constants;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.test.common.AbstractKeycloakTest;
import org.keycloak.test.common.SessionFactoryTestContext;
-
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -163,9 +167,7 @@ public class AdapterTest extends AbstractKeycloakTest {
test1CreateRealm();
OAuthClientModel oauth = new OAuthClientManager(realmModel).create("oauth-client");
- oauth.setBaseUrl("/foo/bar");
oauth = realmModel.getOAuthClient("oauth-client");
- Assert.assertEquals("/foo/bar", oauth.getBaseUrl());
Assert.assertTrue(realmModel.hasRole(oauth.getOAuthAgent(), Constants.IDENTITY_REQUESTER_ROLE));
diff --git a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
old mode 100644
new mode 100755
index 5d0de1a..a5e2a01
--- a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
+++ b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
@@ -4,7 +4,12 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.keycloak.models.*;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
@@ -13,8 +18,6 @@ import org.keycloak.services.resources.KeycloakApplication;
import java.util.Iterator;
import java.util.List;
-import static org.junit.Assert.assertNotNull;
-
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/services/src/test/java/org/keycloak/test/common/AbstractKeycloakTest.java b/services/src/test/java/org/keycloak/test/common/AbstractKeycloakTest.java
index 0656f98..a6debbf 100755
--- a/services/src/test/java/org/keycloak/test/common/AbstractKeycloakTest.java
+++ b/services/src/test/java/org/keycloak/test/common/AbstractKeycloakTest.java
@@ -1,9 +1,5 @@
package org.keycloak.test.common;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -15,6 +11,9 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -34,7 +33,8 @@ public abstract class AbstractKeycloakTest {
{
// TODO: MongoDB disabled by default
TEST_CONTEXTS = new SessionFactoryTestContext[] {
- new PicketlinkSessionFactoryTestContext(),
+ //new PicketlinkSessionFactoryTestContext(),
+ new JpaSessionFactoryTestContext(),
// new MongoDBSessionFactoryTestContext()
};
}
diff --git a/services/src/test/java/org/keycloak/test/common/JpaSessionFactoryTestContext.java b/services/src/test/java/org/keycloak/test/common/JpaSessionFactoryTestContext.java
new file mode 100755
index 0000000..94b8066
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/common/JpaSessionFactoryTestContext.java
@@ -0,0 +1,24 @@
+package org.keycloak.test.common;
+
+import org.keycloak.services.utils.PropertiesManager;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JpaSessionFactoryTestContext implements SessionFactoryTestContext {
+
+ @Override
+ public void beforeTestClass() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void afterTestClass() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void initEnvironment() {
+ PropertiesManager.setSessionFactoryType(PropertiesManager.SESSION_FACTORY_JPA);
+ }
+}
diff --git a/services/src/test/java/org/keycloak/test/common/MongoDBSessionFactoryTestContext.java b/services/src/test/java/org/keycloak/test/common/MongoDBSessionFactoryTestContext.java
old mode 100644
new mode 100755
index def3f34..1b00fa5
--- a/services/src/test/java/org/keycloak/test/common/MongoDBSessionFactoryTestContext.java
+++ b/services/src/test/java/org/keycloak/test/common/MongoDBSessionFactoryTestContext.java
@@ -7,7 +7,6 @@ import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
import org.jboss.resteasy.logging.Logger;
-import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.utils.PropertiesManager;
/**
diff --git a/services/src/test/java/org/keycloak/test/common/PicketlinkSessionFactoryTestContext.java b/services/src/test/java/org/keycloak/test/common/PicketlinkSessionFactoryTestContext.java
old mode 100644
new mode 100755
index 80b2cbc..d152f3b
--- a/services/src/test/java/org/keycloak/test/common/PicketlinkSessionFactoryTestContext.java
+++ b/services/src/test/java/org/keycloak/test/common/PicketlinkSessionFactoryTestContext.java
@@ -1,6 +1,5 @@
package org.keycloak.test.common;
-import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.utils.PropertiesManager;
/**
diff --git a/services/src/test/java/org/keycloak/test/ImportTest.java b/services/src/test/java/org/keycloak/test/ImportTest.java
index febdc39..9bd13f9 100755
--- a/services/src/test/java/org/keycloak/test/ImportTest.java
+++ b/services/src/test/java/org/keycloak/test/ImportTest.java
@@ -1,24 +1,16 @@
package org.keycloak.test;
-import org.junit.After;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
-import org.keycloak.services.resources.KeycloakApplication;
-import org.keycloak.services.resources.SaasService;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.test.common.AbstractKeycloakTest;
import org.keycloak.test.common.SessionFactoryTestContext;
diff --git a/services/src/test/java/org/keycloak/test/ModelTest.java b/services/src/test/java/org/keycloak/test/ModelTest.java
index 9b244be..33eb405 100755
--- a/services/src/test/java/org/keycloak/test/ModelTest.java
+++ b/services/src/test/java/org/keycloak/test/ModelTest.java
@@ -1,22 +1,21 @@
package org.keycloak.test;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
public class ModelTest extends AbstractKeycloakServerTest {
private KeycloakSessionFactory factory;
private KeycloakSession identitySession;
diff --git a/services/src/test/java/org/keycloak/test/UserModelTest.java b/services/src/test/java/org/keycloak/test/UserModelTest.java
old mode 100644
new mode 100755
index 9029511..910a20c
--- a/services/src/test/java/org/keycloak/test/UserModelTest.java
+++ b/services/src/test/java/org/keycloak/test/UserModelTest.java
@@ -1,8 +1,5 @@
package org.keycloak.test;
-import java.util.Iterator;
-import java.util.List;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -16,6 +13,9 @@ import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
+import java.util.Iterator;
+import java.util.List;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -89,6 +89,9 @@ public class UserModelTest extends AbstractKeycloakServerTest {
Assert.assertTrue(user.getRequiredActions().isEmpty());
user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
+ String id = realm.getId();
+ commit();
+ realm = manager.getRealm(id);
user = realm.getUser("user");
Assert.assertEquals(1, user.getRequiredActions().size());
@@ -119,6 +122,14 @@ public class UserModelTest extends AbstractKeycloakServerTest {
Assert.assertTrue(user.getRequiredActions().isEmpty());
}
+ protected void commit() {
+ identitySession.getTransaction().commit();
+ identitySession.close();
+ identitySession = factory.createSession();
+ identitySession.getTransaction().begin();
+ manager = new RealmManager(identitySession);
+ }
+
public static void assertEquals(UserModel expected, UserModel actual) {
Assert.assertEquals(expected.getLoginName(), actual.getLoginName());
Assert.assertEquals(expected.getFirstName(), actual.getFirstName());
diff --git a/services/src/test/resources/META-INF/persistence.xml b/services/src/test/resources/META-INF/persistence.xml
index c17ec56..ae026ef 100755
--- a/services/src/test/resources/META-INF/persistence.xml
+++ b/services/src/test/resources/META-INF/persistence.xml
@@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="picketlink-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
@@ -34,5 +34,36 @@
</properties>
</persistence-unit>
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.RoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
+
+ <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+ <properties>
+ <property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
+ <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
+ <property name="hibernate.connection.username" value="sa"/>
+ <property name="hibernate.connection.password" value=""/>
+ <property name="hibernate.hbm2ddl.auto" value="create-drop" />
+ <property name="hibernate.show_sql" value="false" />
+ <property name="hibernate.format_sql" value="true" />
+ </properties>
+ </persistence-unit>
+
+
</persistence>
diff --git a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
old mode 100644
new mode 100755
index d19f0c7..ac9bc86
--- a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
+++ b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
@@ -1,15 +1,5 @@
package org.keycloak.social.facebook;
-import java.net.URI;
-import java.util.UUID;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Form;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.social.AuthCallback;
@@ -19,6 +9,15 @@ import org.keycloak.social.SocialProviderConfig;
import org.keycloak.social.SocialProviderException;
import org.keycloak.social.SocialUser;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.net.URI;
+import java.util.UUID;
+
/**
* Social provider for Facebook
*
diff --git a/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java b/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java
old mode 100644
new mode 100755
diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
old mode 100644
new mode 100755
index 6ea93c8..8f7a508
--- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
+++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
@@ -27,7 +27,6 @@ import org.keycloak.social.SocialProvider;
import org.keycloak.social.SocialProviderConfig;
import org.keycloak.social.SocialProviderException;
import org.keycloak.social.SocialUser;
-
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.auth.RequestToken;
testsuite/integration/pom.xml 2(+2 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
old mode 100644
new mode 100755
index a411b48..ffbe981
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -81,6 +81,7 @@
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
+ <!--
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-api</artifactId>
@@ -101,6 +102,7 @@
<groupId>org.picketlink</groupId>
<artifactId>picketlink-config</artifactId>
</dependency>
+ -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
index cceefaa..1d5f43e 100755
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
@@ -23,31 +23,42 @@ package org.keycloak.testutils;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
-import io.undertow.server.handlers.resource.*;
+import io.undertow.server.handlers.resource.FileResource;
+import io.undertow.server.handlers.resource.FileResourceManager;
+import io.undertow.server.handlers.resource.Resource;
+import io.undertow.server.handlers.resource.ResourceChangeListener;
+import io.undertow.server.handlers.resource.ResourceManager;
+import io.undertow.server.handlers.resource.URLResource;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DefaultServletConfig;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
-
-import java.io.*;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.servlet.DispatcherType;
-
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import org.jboss.resteasy.spi.ResteasyDeployment;
-import org.keycloak.models.*;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
+import javax.servlet.DispatcherType;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -251,8 +262,7 @@ public class KeycloakServer {
di.setDeploymentName("Keycloak");
di.setResourceManager(new KeycloakResourceManager(config.getResourcesHome()));
- Set<String> allowed = new HashSet<String>(Arrays.asList(new String[]{"js", "css", "png", "jpg", "gif", "html", "svg"}));
- di.setDefaultServletConfig(new DefaultServletConfig(false, allowed));
+ di.setDefaultServletConfig(new DefaultServletConfig(true));
di.addWelcomePage("index.html");
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
@@ -316,6 +326,24 @@ public class KeycloakServer {
return new FileResource(file, new FileResourceManager(file.getParentFile(), 1), path);
}
}
+
+ @Override
+ public boolean isResourceChangeListenerSupported() {
+ return false;
+ }
+
+ @Override
+ public void registerResourceChangeListener(ResourceChangeListener listener) {
+ }
+
+ @Override
+ public void removeResourceChangeListener(ResourceChangeListener listener) {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
}
private static File file(String... path) {
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/MailServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/MailServer.java
old mode 100644
new mode 100755
index 8ba730a..fd9ad22
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/MailServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/MailServer.java
@@ -1,11 +1,11 @@
package org.keycloak.testutils;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMessage.RecipientType;
-
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+
public class MailServer {
public static void main(String[] args) throws Exception {
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/TotpGenerator.java b/testsuite/integration/src/main/java/org/keycloak/testutils/TotpGenerator.java
old mode 100644
new mode 100755
index bc5f633..ff0ac20
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/TotpGenerator.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/TotpGenerator.java
@@ -1,11 +1,12 @@
package org.keycloak.testutils;
+import org.keycloak.models.utils.Base32;
+import org.keycloak.models.utils.TimeBasedOTP;
+
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
-import org.picketlink.common.util.Base32;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
public class TotpGenerator {
diff --git a/testsuite/integration/src/main/resources/META-INF/persistence.xml b/testsuite/integration/src/main/resources/META-INF/persistence.xml
index c17ec56..f299e7e 100755
--- a/testsuite/integration/src/main/resources/META-INF/persistence.xml
+++ b/testsuite/integration/src/main/resources/META-INF/persistence.xml
@@ -2,24 +2,22 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
- <class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
- <class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
- <class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.RoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
old mode 100644
new mode 100755
index 9891af0..e3fe2dd
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
@@ -12,7 +12,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.Constants;
import org.keycloak.testsuite.OAuthClient;
@@ -52,6 +54,16 @@ public class ProfileTest {
user.setAttribute("key2", "value2");
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
+ for (String r : accountApp.getDefaultRoles()) {
+ accountApp.grantRole(user, accountApp.getRole(r));
+ }
+
+ UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
+ user2.setEnabled(true);
+ UserCredentialModel creds = new UserCredentialModel();
+ creds.setType(CredentialRepresentation.PASSWORD);
+ creds.setValue("password");
+ appRealm.updateCredential(user2, creds);
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
accountApp.addScopeMapping(app.getApplicationUser(), org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
@@ -81,8 +93,6 @@ public class ProfileTest {
@WebResource
protected OAuthGrantPage grantPage;
- private List<String> defaultRoles;
-
@Test
public void getProfile() throws Exception {
oauth.doLogin("test-user@localhost", "password");
@@ -154,31 +164,13 @@ public class ProfileTest {
@Test
public void getProfileNoAccess() throws Exception {
- try {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
- @Override
- public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- ApplicationModel app = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
- defaultRoles = app.getDefaultRoles();
- app.updateDefaultRoles(new String[0]);
- }
- });
-
- oauth.doLogin("test-user@localhost", "password");
-
- String code = oauth.getCurrentQuery().get("code");
- String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
-
- HttpResponse response = doGetProfile(token, null);
- assertEquals(403, response.getStatusLine().getStatusCode());
- } finally {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
- @Override
- public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray());
- }
- });
- }
+ oauth.doLogin("test-user-no-access@localhost", "password");
+
+ String code = oauth.getCurrentQuery().get("code");
+ String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+
+ HttpResponse response = doGetProfile(token, null);
+ assertEquals(403, response.getStatusLine().getStatusCode());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
index 8b27729..7909d83 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
@@ -21,21 +21,14 @@
*/
package org.keycloak.testsuite.actions;
-import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.LoginPage;
@@ -48,6 +41,12 @@ import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
index d591829..917d047 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
@@ -25,10 +25,10 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.LoginPage;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
index 76757f4..28197d0 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
@@ -25,10 +25,10 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java
index bb70d97..4829158 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java
@@ -25,11 +25,10 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AccountTotpPage;
import org.keycloak.testsuite.pages.AppPage;
@@ -42,7 +41,6 @@ import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
index c567e99..0b66340 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
@@ -22,13 +22,12 @@
package org.keycloak.testsuite.actions;
import org.junit.Assert;
-import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.LoginPage;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/ApplicationServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/ApplicationServlet.java
old mode 100644
new mode 100755
index 4202cc1..9aa9655
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/ApplicationServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/ApplicationServlet.java
@@ -21,19 +21,18 @@
*/
package org.keycloak.testsuite;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
old mode 100644
new mode 100755
index 32ab6bf..bab9f43
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
@@ -1,7 +1,5 @@
package org.keycloak.testsuite;
-import java.util.UUID;
-
import org.keycloak.social.AuthCallback;
import org.keycloak.social.AuthRequest;
import org.keycloak.social.SocialProvider;
@@ -9,6 +7,8 @@ import org.keycloak.social.SocialProviderConfig;
import org.keycloak.social.SocialProviderException;
import org.keycloak.social.SocialUser;
+import java.util.UUID;
+
public class DummySocial implements SocialProvider {
private static final String AUTH_PATH = "http://localhost:8081/dummy-social/auth";
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
old mode 100644
new mode 100755
index d7b1e37..f6cc0d0
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
@@ -1,17 +1,16 @@
package org.keycloak.testsuite;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.charset.Charset;
-import java.util.List;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.List;
public class DummySocialServlet extends HttpServlet {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
index f7bc811..4d0d3ca 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
@@ -24,6 +24,7 @@ package org.keycloak.testsuite.forms;
import org.apache.http.HttpResponse;
import org.junit.*;
import org.keycloak.models.*;
+import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
@@ -36,7 +37,6 @@ import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
import java.util.List;
@@ -48,7 +48,23 @@ import static org.junit.Assert.assertEquals;
public class AccountTest {
@ClassRule
- public static KeycloakRule keycloakRule = new KeycloakRule();
+ public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ UserModel user = appRealm.getUser("test-user@localhost");
+ ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
+ for (String r : accountApp.getDefaultRoles()) {
+ accountApp.grantRole(user, accountApp.getRole(r));
+ }
+
+ UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
+ user2.setEnabled(true);
+ UserCredentialModel creds = new UserCredentialModel();
+ creds.setType(CredentialRepresentation.PASSWORD);
+ creds.setValue("password");
+ appRealm.updateCredential(user2, creds);
+ }
+ });
@Rule
public WebRule webRule = new WebRule(this);
@@ -79,8 +95,6 @@ public class AccountTest {
private TimeBasedOTP totp = new TimeBasedOTP();
- private List<String> defaultRoles;
-
@After
public void after() {
keycloakRule.configure(new KeycloakSetup() {
@@ -119,7 +133,7 @@ public class AccountTest {
loginPage.open();
loginPage.login("test-user@localhost", "password");
- Assert.assertEquals("Invalid username or password", loginPage.getError());
+ Assert.assertEquals("Invalid username or password.", loginPage.getError());
loginPage.open();
loginPage.login("test-user@localhost", "new-password");
@@ -176,7 +190,7 @@ public class AccountTest {
Assert.assertFalse(driver.getPageSource().contains("Remove Google"));
// Error with false code
- totpPage.configure(totp.generate(totpPage.getTotpSecret()+"123"));
+ totpPage.configure(totp.generate(totpPage.getTotpSecret() + "123"));
Assert.assertTrue(profilePage.isError());
@@ -189,29 +203,11 @@ public class AccountTest {
@Test
public void changeProfileNoAccess() throws Exception {
- try {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
- @Override
- public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- ApplicationModel app = appRealm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
- defaultRoles = app.getDefaultRoles();
- app.updateDefaultRoles(new String[0]);
- }
- });
-
- profilePage.open();
- loginPage.login("test-user@localhost", "password");
-
- Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("No access", errorPage.getError());
- } finally {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
- @Override
- public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray());
- }
- });
- }
+ profilePage.open();
+ loginPage.login("test-user-no-access@localhost", "password");
+
+ Assert.assertTrue(errorPage.isCurrent());
+ Assert.assertEquals("No access", errorPage.getError());
}
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index d9628df..fab49b2 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -60,7 +60,7 @@ public class LoginTest {
loginPage.assertCurrent();
- Assert.assertEquals("Invalid username or password", loginPage.getError());
+ Assert.assertEquals("Invalid username or password.", loginPage.getError());
}
@Test
@@ -70,7 +70,7 @@ public class LoginTest {
loginPage.assertCurrent();
- Assert.assertEquals("Invalid username or password", loginPage.getError());
+ Assert.assertEquals("Invalid username or password.", loginPage.getError());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 2ff938b..a3ea179 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -21,18 +21,17 @@
*/
package org.keycloak.testsuite.forms;
-import java.net.MalformedURLException;
-
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.TimeBasedOTP;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.LoginPage;
@@ -43,7 +42,8 @@ import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
-import org.picketlink.idm.credential.util.TimeBasedOTP;
+
+import java.net.MalformedURLException;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -102,7 +102,7 @@ public class LoginTotpTest {
loginTotpPage.login("123456");
loginPage.assertCurrent();
- Assert.assertEquals("Invalid username or password", loginPage.getError());
+ Assert.assertEquals("Invalid username or password.", loginPage.getError());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
index 93e773e..e82b31f 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
@@ -90,7 +90,7 @@ public class RegisterTest {
registerPage.register("firstName", "lastName", "email", "registerUserMissingPassword", null, null);
registerPage.assertCurrent();
- Assert.assertEquals("Please specify password", registerPage.getError());
+ Assert.assertEquals("Please specify password.", registerPage.getError());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
old mode 100644
new mode 100755
index 396f3d9..2610ff5
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -21,11 +21,6 @@
*/
package org.keycloak.testsuite.forms;
-import java.io.IOException;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
@@ -42,6 +37,10 @@ import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.io.IOException;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
old mode 100644
new mode 100755
index 2ccd506..017aca5
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -21,9 +21,6 @@
*/
package org.keycloak.testsuite.oauth;
-import java.io.IOException;
-
-import org.apache.http.client.ClientProtocolException;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
@@ -41,6 +38,8 @@ import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
+import java.io.IOException;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
old mode 100644
new mode 100755
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
old mode 100644
new mode 100755
index 2a0e372..c69208f
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -21,17 +21,6 @@
*/
package org.keycloak.testsuite;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.security.PublicKey;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import javax.ws.rs.core.UriBuilder;
-
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
@@ -53,6 +42,16 @@ import org.keycloak.representations.SkeletonKeyToken;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
+import javax.ws.rs.core.UriBuilder;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractAccountPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractAccountPage.java
old mode 100644
new mode 100755
index 9860b14..d849330
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractAccountPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractAccountPage.java
@@ -21,9 +21,6 @@
*/
package org.keycloak.testsuite.pages;
-import org.junit.Assert;
-import org.keycloak.testsuite.rule.WebResource;
-import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/GreenMailRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/GreenMailRule.java
old mode 100644
new mode 100755
index 386ddb7..bd52a59
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/GreenMailRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/GreenMailRule.java
@@ -21,18 +21,13 @@
*/
package org.keycloak.testsuite.rule;
-import java.lang.Thread.UncaughtExceptionHandler;
-import java.net.SocketException;
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import javax.mail.internet.MimeMessage;
-
-import org.junit.rules.ExternalResource;
-
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
+import org.junit.rules.ExternalResource;
+
+import javax.mail.internet.MimeMessage;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.net.SocketException;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
index 010b1cc..cdbcfe1 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
@@ -23,13 +23,6 @@ package org.keycloak.testsuite.rule;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.ServletInfo;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.servlet.Servlet;
-
import org.jboss.resteasy.jwt.JsonSerialization;
import org.junit.rules.ExternalResource;
import org.keycloak.models.Constants;
@@ -40,6 +33,11 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.ApplicationServlet;
import org.keycloak.testutils.KeycloakServer;
+import javax.servlet.Servlet;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
old mode 100644
new mode 100755
index ccdca44..ef37e21
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
@@ -21,8 +21,7 @@
*/
package org.keycloak.testsuite.rule;
-import java.lang.reflect.Field;
-
+import com.gargoylesoftware.htmlunit.WebClient;
import org.junit.rules.ExternalResource;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AbstractPage;
@@ -31,7 +30,7 @@ import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.PageFactory;
-import com.gargoylesoftware.htmlunit.WebClient;
+import java.lang.reflect.Field;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/social/SocialLoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/social/SocialLoginTest.java
index 4f87a10..e4c3c6f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/social/SocialLoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/social/SocialLoginTest.java
@@ -26,9 +26,9 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.models.RealmModel;
import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.models.RealmModel;
import org.keycloak.testsuite.DummySocialServlet;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
@@ -44,7 +44,6 @@ import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import java.util.HashMap;
-import java.util.Map;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -104,9 +103,6 @@ public class SocialLoginTest {
SkeletonKeyToken token = oauth.verifyToken(response.getAccessToken());
Assert.assertEquals("dummy-user", token.getPrincipal());
-
- Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
- Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
}
@Test
testsuite/performance/pom.xml 2(+2 -0)
diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml
old mode 100644
new mode 100755
index 1cb8220..f9dc957
--- a/testsuite/performance/pom.xml
+++ b/testsuite/performance/pom.xml
@@ -146,6 +146,7 @@
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
+ <!--
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
@@ -161,6 +162,7 @@
<artifactId>picketlink-config</artifactId>
<version>${picketlink.version}</version>
</dependency>
+ -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
old mode 100644
new mode 100755
index efe57c1..882f8bb
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
@@ -1,9 +1,5 @@
package org.keycloak.testsuite.performance;
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
@@ -12,6 +8,10 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.services.resources.KeycloakApplication;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
old mode 100644
new mode 100755
index 2749998..c839337
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
@@ -1,7 +1,5 @@
package org.keycloak.testsuite.performance;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
@@ -11,6 +9,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
old mode 100644
new mode 100755
index 67d2ca6..12fced6
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
@@ -1,7 +1,5 @@
package org.keycloak.testsuite.performance;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
@@ -13,6 +11,8 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
old mode 100644
new mode 100755
index 416cd60..737fc21
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
@@ -1,7 +1,5 @@
package org.keycloak.testsuite.performance;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
@@ -10,6 +8,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/RemoveUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/RemoveUsersWorker.java
old mode 100644
new mode 100755
index 262ad93..b13b7d1
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/RemoveUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/RemoveUsersWorker.java
@@ -1,13 +1,12 @@
package org.keycloak.testsuite.performance;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.services.utils.PropertiesManager;
+
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
diff --git a/testsuite/performance/src/test/resources/META-INF/persistence.xml b/testsuite/performance/src/test/resources/META-INF/persistence.xml
old mode 100644
new mode 100755
index 1dff641..8083104
--- a/testsuite/performance/src/test/resources/META-INF/persistence.xml
+++ b/testsuite/performance/src/test/resources/META-INF/persistence.xml
@@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="picketlink-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
@@ -18,8 +18,39 @@
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
- <class>org.keycloak.services.models.picketlink.mappings.RealmEntity</class>
- <class>org.keycloak.services.models.picketlink.mappings.ApplicationEntity</class>
+ <class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
+ <class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
+
+ <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+ <properties>
+ <property name="hibernate.connection.url" value="jdbc:mysql://localhost/keycloakPerfTest"/>
+ <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
+ <property name="hibernate.connection.username" value="portal"/>
+ <property name="hibernate.connection.password" value="portal"/>
+ <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
+ <!--<property name="hibernate.hbm2ddl.auto" value="update" />-->
+ <property name="hibernate.hbm2ddl.auto" value="${keycloak.jpa.hbm2ddl.auto}" />
+ <property name="hibernate.show_sql" value="false" />
+ <property name="hibernate.format_sql" value="true" />
+ </properties>
+ </persistence-unit>
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmScopeMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmUserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.RoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>