keycloak-memoizeit
Changes
examples/js/keycloak.js 216(+97 -119)
examples/js/testrealm.json 1(+1 -0)
examples/js-google/index.html 24(+24 -0)
examples/js-google/keycloak.js 139(+139 -0)
examples/js-google/keycloak.js.orig 222(+222 -0)
examples/js-google/kinvey.html 13(+13 -0)
examples/js-google/testrealm.json 60(+60 -0)
Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index 7b7fa9d..878092e 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -21,6 +21,7 @@ public class ApplicationRepresentation {
protected List<UserRoleMappingRepresentation> roleMappings;
protected List<ScopeMappingRepresentation> scopeMappings;
protected List<String> redirectUris;
+ protected List<String> webOrigins;
public String getSelf() {
return self;
@@ -155,4 +156,12 @@ public class ApplicationRepresentation {
public void setRedirectUris(List<String> redirectUris) {
this.redirectUris = redirectUris;
}
+
+ public List<String> getWebOrigins() {
+ return webOrigins;
+ }
+
+ public void setWebOrigins(List<String> webOrigins) {
+ this.webOrigins = webOrigins;
+ }
}
examples/js/keycloak.js 216(+97 -119)
diff --git a/examples/js/keycloak.js b/examples/js/keycloak.js
index dfb6ebb..480996d 100644
--- a/examples/js/keycloak.js
+++ b/examples/js/keycloak.js
@@ -1,120 +1,98 @@
-window.keycloak = (function() {
- var kc = {};
- var config = null;
-
- kc.init = function(c) {
- config = c;
-
- var token = getTokenFromCode();
- if (token) {
- var t = parseToken(token);
- kc.user = t.prn;
- kc.authenticated = true;
- } else {
- kc.authenticated = false;
- }
- }
-
- kc.login = function() {
- var clientId = encodeURIComponent(config.clientId);
- var redirectUri = encodeURIComponent(window.location.href);
- var state = encodeURIComponent(createUUID());
- var realm = encodeURIComponent(config.realm);
- var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
- + '&state=' + state;
- window.location.href = url;
- }
-
- return kc;
-
- function parseToken(token) {
- var t = base64Decode(token.split('.')[1]);
- return JSON.parse(t);
- }
-
- function getTokenFromCode() {
- var code = getQueryParam('code');
- if (code) {
- window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
-
- var clientId = encodeURIComponent(config.clientId);
- var clientSecret = encodeURIComponent(config.clientSecret);
- var realm = encodeURIComponent(config.realm);
-
- var params = 'code=' + code + '&client_id=' + config.clientId + '&password=' + config.clientSecret;
- var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
-
- var http = new XMLHttpRequest();
- http.open('POST', url, false);
- http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
-
- http.send(params);
- if (http.status == 200) {
- return JSON.parse(http.responseText)['access_token'];
- }
- }
- return undefined;
- }
-
- function getQueryParam(name) {
- var params = window.location.search.substring(1).split('&');
- for ( var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- if (decodeURIComponent(p[0]) == name) {
- return p[1];
- }
- }
- }
-
- function createUUID() {
- var s = [];
- var hexDigits = '0123456789abcdef';
- for ( var i = 0; i < 36; i++) {
- s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
- }
- s[14] = '4';
- s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
- s[8] = s[13] = s[18] = s[23] = '-';
- var uuid = s.join('');
- return uuid;
- }
-
- function base64Decode (data) {
- var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
- ac = 0,
- dec = "",
- tmp_arr = [];
-
- if (!data) {
- return data;
- }
-
- data += '';
-
- do {
- h1 = b64.indexOf(data.charAt(i++));
- h2 = b64.indexOf(data.charAt(i++));
- h3 = b64.indexOf(data.charAt(i++));
- h4 = b64.indexOf(data.charAt(i++));
-
- bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
-
- o1 = bits >> 16 & 0xff;
- o2 = bits >> 8 & 0xff;
- o3 = bits & 0xff;
-
- if (h3 == 64) {
- tmp_arr[ac++] = String.fromCharCode(o1);
- } else if (h4 == 64) {
- tmp_arr[ac++] = String.fromCharCode(o1, o2);
- } else {
- tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
- }
- } while (i < data.length);
-
- dec = tmp_arr.join('');
-
- return dec;
- }
+window.keycloak = (function () {
+ var kc = {};
+ var config = {
+ baseUrl: null,
+ clientId: null,
+ clientSecret: null,
+ realm: null
+ };
+
+ kc.init = function (c) {
+ for (var prop in config) {
+ if (c[prop]) {
+ config[prop] = c[prop];
+ }
+
+ if (!config[prop]) {
+ throw new Error(prop + 'not defined');
+ }
+ }
+
+ var token = getTokenFromCode();
+ if (token) {
+ var t = parseToken(token);
+ kc.user = t.prn;
+ kc.authenticated = true;
+ kc.token = token;
+ } else {
+ kc.authenticated = false;
+ }
+ }
+
+ kc.login = function () {
+ var clientId = encodeURIComponent(config.clientId);
+ var redirectUri = encodeURIComponent(window.location.href);
+ var state = encodeURIComponent(createUUID());
+ var realm = encodeURIComponent(config.realm);
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
+ + '&state=' + state;
+
+ sessionStorage.state = state;
+
+ window.location.href = url;
+ }
+
+ return kc;
+
+ function parseToken(token) {
+ return JSON.parse(atob(token.split('.')[1]));
+ }
+
+ function getTokenFromCode() {
+ var code = getQueryParam('code');
+ var state = getQueryParam('state');
+ if (code && state === sessionStorage.state) {
+ window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
+
+ var clientId = encodeURIComponent(config.clientId);
+ var clientSecret = encodeURIComponent(config.clientSecret);
+ var realm = encodeURIComponent(config.realm);
+
+ var params = 'code=' + code + '&client_id=' + clientId + '&password=' + clientSecret;
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
+
+ var http = new XMLHttpRequest();
+ http.open('POST', url, false);
+ http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+ http.send(params);
+ if (http.status == 200) {
+ return JSON.parse(http.responseText)['access_token'];
+ }
+ }
+ return undefined;
+ }
+
+ function getQueryParam(name) {
+ var params = window.location.search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ if (decodeURIComponent(p[0]) == name) {
+ return p[1];
+ }
+ }
+ }
+
+ function createUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for (var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4';
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+ s[8] = s[13] = s[18] = s[23] = '-';
+ var uuid = s.join('');
+ return uuid;
+ }
})();
\ No newline at end of file
examples/js/testrealm.json 1(+1 -0)
diff --git a/examples/js/testrealm.json b/examples/js/testrealm.json
index 824fe14..2468f48 100755
--- a/examples/js/testrealm.json
+++ b/examples/js/testrealm.json
@@ -48,6 +48,7 @@
"enabled": true,
"adminUrl": "http://localhost:8081/app/logout",
"useRealmMappings": true,
+ "webOrigins": [ "http://localhost", "http://localhost:8000", "http://localhost:8080" ],
"credentials": [
{
"type": "password",
examples/js-google/index.html 24(+24 -0)
diff --git a/examples/js-google/index.html b/examples/js-google/index.html
new file mode 100644
index 0000000..7a72120
--- /dev/null
+++ b/examples/js-google/index.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="keycloak.js"></script>
+</head>
+<body>
+ <script>
+ keycloak.init({
+ clientId : '57572475438.apps.googleusercontent.com',
+ clientSecret : 'xyfsPS9maRTz5fj0pOxf0zjD'
+ });
+
+ if (keycloak.authenticated) {
+ document.write('<h2>Token</h2><pre>' + keycloak.token + '</pre>');
+ document.write('<h2>Token info</h2><pre>' + JSON.stringify(keycloak.tokenInfo, undefined, 4) + '</pre>');
+ document.write('<h2>Profile</h2><pre>' + JSON.stringify(keycloak.profile(true), undefined, 4) + '</pre>');
+ document.write('<h2>Contacts</h2><pre>' + keycloak.contacts(true) + '</pre>');
+ } else {
+ document.write('<a href="#" id="login" onclick="keycloak.login()">Login</a>');
+ }
+ </script>
+
+</body>
+</html>
examples/js-google/keycloak.js 139(+139 -0)
diff --git a/examples/js-google/keycloak.js b/examples/js-google/keycloak.js
new file mode 100644
index 0000000..172557d
--- /dev/null
+++ b/examples/js-google/keycloak.js
@@ -0,0 +1,139 @@
+window.keycloak = (function () {
+ var kc = {};
+ var config = {
+ clientId: null,
+ clientSecret: null
+ };
+
+ kc.init = function (c) {
+ for (var prop in config) {
+ if (c[prop]) {
+ config[prop] = c[prop];
+ }
+
+ if (!config[prop]) {
+ throw new Error(prop + ' not defined');
+ }
+ }
+
+ loadToken();
+
+ if (kc.token) {
+ kc.user = kc.tokenInfo.user_id;
+ kc.authenticated = true;
+ } else {
+ kc.authenticated = false;
+ kc.user = null;
+ }
+ }
+
+ kc.login = function () {
+ var clientId = encodeURIComponent(config.clientId);
+ var redirectUri = encodeURIComponent(window.location.href);
+ var state = encodeURIComponent(createUUID());
+ var scope = encodeURIComponent('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.login');
+ var url = 'https://accounts.google.com/o/oauth2/auth?response_type=token&client_id=' + clientId + '&redirect_uri=' + redirectUri
+ + '&state=' + state + '&scope=' + scope;
+
+ sessionStorage.state = state;
+
+ window.location.href = url;
+ }
+
+ function parseToken(token) {
+ return JSON.parse(atob(token.split('.')[1]));
+ }
+
+ kc.profile = function(header) {
+ var url = 'https://www.googleapis.com/oauth2/v1/userinfo'
+
+ if (!header) {
+ url = url + '?access_token=' + kc.token;
+ }
+
+ var http = new XMLHttpRequest();
+ http.open('GET', url, false);
+ if (header) {
+ http.setRequestHeader('Authorization', 'Bearer ' + kc.token);
+ }
+
+ http.send();
+ if (http.status == 200) {
+ return JSON.parse(http.responseText);
+ }
+ }
+
+ kc.contacts = function(header) {
+ var url = 'https://www.googleapis.com/plus/v1/people/me';
+
+ if (!header) {
+ url = url + '?access_token=' + kc.token;
+ }
+
+ var http = new XMLHttpRequest();
+ http.open('GET', url, false);
+ if (header) {
+ http.setRequestHeader('Authorization', 'Bearer ' + kc.token);
+ }
+
+ http.send();
+ if (http.status == 200) {
+ return http.responseText;
+ }
+ }
+
+ return kc;
+
+ function loadToken() {
+ var params = {}
+ var queryString = location.hash.substring(1)
+ var regex = /([^&=]+)=([^&]*)/g, m;
+ while (m = regex.exec(queryString)) {
+ params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
+ }
+
+ var token = params['access_token'];
+ var state = params['state'];
+
+ if (token && state === sessionStorage.state) {
+ window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
+
+ kc.token = token;
+
+ var url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + token;
+
+ var http = new XMLHttpRequest();
+ http.open('GET', url, false);
+
+ http.send();
+ if (http.status == 200) {
+ kc.tokenInfo = JSON.parse(http.responseText);
+ }
+ }
+ return undefined;
+ }
+
+ function getQueryParam(name) {
+ console.debug(window.location.hash);
+ var params = window.location.hash.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ if (decodeURIComponent(p[0]) == name) {
+ return p[1];
+ }
+ }
+ }
+
+ function createUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for (var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4';
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+ s[8] = s[13] = s[18] = s[23] = '-';
+ var uuid = s.join('');
+ return uuid;
+ }
+})();
examples/js-google/keycloak.js.orig 222(+222 -0)
diff --git a/examples/js-google/keycloak.js.orig b/examples/js-google/keycloak.js.orig
new file mode 100644
index 0000000..439d2af
--- /dev/null
+++ b/examples/js-google/keycloak.js.orig
@@ -0,0 +1,222 @@
+<<<<<<< Updated upstream
+window.keycloak = (function() {
+ var kc = {};
+ var config = null;
+
+ kc.init = function(c) {
+ config = c;
+
+ var token = getTokenFromCode();
+ if (token) {
+ var t = parseToken(token);
+ kc.user = t.prn;
+ kc.authenticated = true;
+ } else {
+ kc.authenticated = false;
+ }
+ }
+
+ kc.login = function() {
+ var clientId = encodeURIComponent(config.clientId);
+ var redirectUri = encodeURIComponent(window.location.href);
+ var state = encodeURIComponent(createUUID());
+ var realm = encodeURIComponent(config.realm);
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
+ + '&state=' + state;
+ window.location.href = url;
+ }
+
+ return kc;
+
+ function parseToken(token) {
+ return JSON.parse(atob(token.split('.')[1]));
+ }
+
+ function getTokenFromCode() {
+ var code = getQueryParam('code');
+ if (code) {
+ window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
+
+ var clientId = encodeURIComponent(config.clientId);
+ var clientSecret = encodeURIComponent(config.clientSecret);
+ var realm = encodeURIComponent(config.realm);
+
+ var params = 'code=' + code + '&client_id=' + config.clientId + '&password=' + config.clientSecret;
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
+
+ var http = new XMLHttpRequest();
+ http.open('POST', url, false);
+ http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+ http.send(params);
+ if (http.status == 200) {
+ return JSON.parse(http.responseText)['access_token'];
+ }
+ }
+ return undefined;
+ }
+
+ function getQueryParam(name) {
+ var params = window.location.search.substring(1).split('&');
+ for ( var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ if (decodeURIComponent(p[0]) == name) {
+ return p[1];
+ }
+ }
+ }
+
+ function createUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for ( var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4';
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+ s[8] = s[13] = s[18] = s[23] = '-';
+ var uuid = s.join('');
+ return uuid;
+ }
+=======
+window.keycloak = (function () {
+ var kc = {};
+ var config = {
+ baseUrl : null,
+ clientId : null,
+ clientSecret: null,
+ realm: null
+ };
+
+ kc.init = function (c) {
+ for (var prop in config) {
+ if (c[prop]) {
+ config[prop] = c[prop];
+ }
+
+ if (!config[prop]) {
+ throw new Error(prop + 'not defined');
+ }
+ }
+
+ var token = getTokenFromCode();
+ if (token) {
+ var t = parseToken(token);
+ kc.user = t.prn;
+ kc.authenticated = true;
+ } else {
+ kc.authenticated = false;
+ }
+ }
+
+ kc.login = function () {
+ var clientId = encodeURIComponent(config.clientId);
+ var redirectUri = encodeURIComponent(window.location.href);
+ var realm = encodeURIComponent(config.realm);
+ var state = encodeURIComponent(createUUID());
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
+ + '&state=' + state;
+
+ sessionStorage.state = state;
+
+ window.location.href = url;
+ }
+
+ return kc;
+
+ function parseToken(token) {
+ var t = base64Decode(token.split('.')[1]);
+ return JSON.parse(t);
+ }
+
+ function getTokenFromCode() {
+ var code = getQueryParam('code');
+ var state = getQueryParam('state');
+
+ if (code) {
+ if (state && state === sessionStorage.state) {
+ window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
+
+ var clientId = encodeURIComponent(config.clientId);
+ var clientSecret = encodeURIComponent(config.clientSecret);
+ var realm = encodeURIComponent(config.realm);
+
+ var params = 'code=' + code + '&client_id=' + clientId + '&password=' + clientSecret;
+ var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
+
+ var http = new XMLHttpRequest();
+ http.open('POST', url, false);
+ http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+ http.send(params);
+ if (http.status == 200) {
+ return JSON.parse(http.responseText)['access_token'];
+ }
+ }
+ }
+ return undefined;
+ }
+
+ function getQueryParam(name) {
+ var params = window.location.search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ if (decodeURIComponent(p[0]) == name) {
+ return p[1];
+ }
+ }
+ }
+
+ function createUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for (var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4';
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+ s[8] = s[13] = s[18] = s[23] = '-';
+ var uuid = s.join('');
+ return uuid;
+ }
+
+ function base64Decode(data) {
+ var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
+ ac = 0,
+ dec = "",
+ tmp_arr = [];
+
+ if (!data) {
+ return data;
+ }
+
+ data += '';
+
+ do {
+ h1 = b64.indexOf(data.charAt(i++));
+ h2 = b64.indexOf(data.charAt(i++));
+ h3 = b64.indexOf(data.charAt(i++));
+ h4 = b64.indexOf(data.charAt(i++));
+
+ bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
+
+ o1 = bits >> 16 & 0xff;
+ o2 = bits >> 8 & 0xff;
+ o3 = bits & 0xff;
+
+ if (h3 == 64) {
+ tmp_arr[ac++] = String.fromCharCode(o1);
+ } else if (h4 == 64) {
+ tmp_arr[ac++] = String.fromCharCode(o1, o2);
+ } else {
+ tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
+ }
+ } while (i < data.length);
+
+ dec = tmp_arr.join('');
+
+ return dec;
+ }
+>>>>>>> Stashed changes
+})();
\ No newline at end of file
examples/js-google/kinvey.html 13(+13 -0)
diff --git a/examples/js-google/kinvey.html b/examples/js-google/kinvey.html
new file mode 100644
index 0000000..9e1324c
--- /dev/null
+++ b/examples/js-google/kinvey.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
+</head>
+<body>
+
+ <script>
+ $.ajax('https://baas.kinvey.com/appdata/kid_PVD-jo1HqO');
+ </script>
+
+</body>
+</html>
examples/js-google/testrealm.json 60(+60 -0)
diff --git a/examples/js-google/testrealm.json b/examples/js-google/testrealm.json
new file mode 100755
index 0000000..2468f48
--- /dev/null
+++ b/examples/js-google/testrealm.json
@@ -0,0 +1,60 @@
+{
+ "id": "test",
+ "realm": "test",
+ "enabled": true,
+ "tokenLifespan": 300,
+ "accessCodeLifespan": 10,
+ "accessCodeLifespanUserAction": 600,
+ "sslNotRequired": true,
+ "cookieLoginAllowed": true,
+ "registrationAllowed": true,
+ "resetPasswordAllowed": true,
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "requiredApplicationCredentials": [ "password" ],
+ "requiredOAuthClientCredentials": [ "password" ],
+ "defaultRoles": [ "user" ],
+ "users" : [
+ {
+ "username" : "test-user@localhost",
+ "enabled": true,
+ "email" : "test-user@localhost",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ]
+ }
+ ],
+ "roles": [
+ {
+ "name": "user",
+ "description": "Have User privileges"
+ },
+ {
+ "name": "admin",
+ "description": "Have Administrator privileges"
+ }
+ ],
+ "roleMappings": [
+ {
+ "username": "test-user@localhost",
+ "roles": ["user"]
+ }
+ ],
+ "applications": [
+ {
+ "name": "test-app",
+ "enabled": true,
+ "adminUrl": "http://localhost:8081/app/logout",
+ "useRealmMappings": true,
+ "webOrigins": [ "http://localhost", "http://localhost:8000", "http://localhost:8080" ],
+ "credentials": [
+ {
+ "type": "password",
+ "value": "password"
+ }
+ ]
+ }
+ ]
+}
diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java
index 8598ae7..7e33185 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -35,6 +35,14 @@ public interface UserModel {
void removeRequiredAction(RequiredAction action);
+ Set<String> getWebOrigins();
+
+ void setWebOrigins(Set<String> webOrigins);
+
+ void addWebOrigin(String webOrigin);
+
+ void removeWebOrigin(String webOrigin);
+
Set<String> getRedirectUris();
void setRedirectUris(Set<String> redirectUris);
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 98894ce..e44c92a 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
@@ -22,6 +22,7 @@ public class UserAdapter implements UserModel {
private static final String REQUIRED_ACTIONS_ATTR = "requiredActions";
private static final String REDIRECT_URIS = "redirectUris";
+ private static final String WEB_ORIGINS = "webOrigins";
protected User user;
protected IdentityManager idm;
@@ -162,6 +163,26 @@ public class UserAdapter implements UserModel {
}
@Override
+ public Set<String> getWebOrigins() {
+ return getAttributeSet(WEB_ORIGINS);
+ }
+
+ @Override
+ public void setWebOrigins(Set<String> webOrigins) {
+ setAttributeSet(WEB_ORIGINS, webOrigins);
+ }
+
+ @Override
+ public void addWebOrigin(String webOrigin) {
+ addToAttributeSet(WEB_ORIGINS, webOrigin);
+ }
+
+ @Override
+ public void removeWebOrigin(String webOrigin) {
+ removeFromAttributeSet(WEB_ORIGINS, webOrigin);
+ }
+
+ @Override
public boolean isTotp() {
Attribute<Boolean> a = user.getAttribute(KEYCLOAK_TOTP_ATTR);
return a != null ? a.getValue() : false;
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 93c2959..9b89cf4 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -42,6 +42,11 @@ public class ApplicationManager {
resourceUser.addRedirectUri(redirectUri);
}
}
+ if (resourceRep.getWebOrigins() != null) {
+ for (String webOrigin : resourceRep.getWebOrigins()) {
+ resourceUser.addWebOrigin(webOrigin);
+ }
+ }
realm.grantRole(resourceUser, loginRole);
@@ -97,6 +102,11 @@ public class ApplicationManager {
if (redirectUris != null) {
resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
}
+
+ List<String> webOrigins = rep.getWebOrigins();
+ if (webOrigins != null) {
+ resource.getApplicationUser().setWebOrigins(new HashSet<String>(webOrigins));
+ }
}
public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
@@ -113,6 +123,11 @@ public class ApplicationManager {
rep.setRedirectUris(new LinkedList<String>(redirectUris));
}
+ Set<String> webOrigins = applicationModel.getApplicationUser().getWebOrigins();
+ if (webOrigins != null) {
+ rep.setWebOrigins(new LinkedList<String>(webOrigins));
+ }
+
return rep;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/Cors.java b/services/src/main/java/org/keycloak/services/resources/Cors.java
new file mode 100644
index 0000000..8c28d6f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/Cors.java
@@ -0,0 +1,43 @@
+package org.keycloak.services.resources;
+
+import java.util.Set;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.jboss.resteasy.spi.HttpRequest;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Cors {
+
+ private HttpRequest request;
+ private ResponseBuilder response;
+ private Set<String> allowedOrigins;
+
+ public Cors(HttpRequest request, ResponseBuilder response) {
+ this.request = request;
+ this.response = response;
+ }
+
+ public static Cors add(HttpRequest request, ResponseBuilder response) {
+ return new Cors(request, response);
+ }
+
+ public Cors allowedOrigins(Set<String> allowedOrigins) {
+ this.allowedOrigins = allowedOrigins;
+ return this;
+ }
+
+ public Response build() {
+ String origin = request.getHttpHeaders().getHeaderString("Origin");
+ if (origin == null || allowedOrigins == null || (!allowedOrigins.contains(origin))) {
+ return response.build();
+ }
+
+ response.header("Access-Control-Allow-Origin", origin);
+ return response.build();
+ }
+
+}
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 d72e80d..7296d8e 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -415,7 +415,8 @@ public class TokenService {
}
logger.info("accessRequest SUCCESS");
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
- return Response.ok(res).build();
+
+ return Cors.add(request, Response.ok(res)).allowedOrigins(client.getWebOrigins()).build();
}
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {