Added cors support to TokenService.accessCodeToToken
This commit is contained in:
parent
1c90e16629
commit
34fe0a751c
13 changed files with 639 additions and 105 deletions
|
@ -21,6 +21,7 @@ public class ApplicationRepresentation {
|
||||||
protected List<UserRoleMappingRepresentation> roleMappings;
|
protected List<UserRoleMappingRepresentation> roleMappings;
|
||||||
protected List<ScopeMappingRepresentation> scopeMappings;
|
protected List<ScopeMappingRepresentation> scopeMappings;
|
||||||
protected List<String> redirectUris;
|
protected List<String> redirectUris;
|
||||||
|
protected List<String> webOrigins;
|
||||||
|
|
||||||
public String getSelf() {
|
public String getSelf() {
|
||||||
return self;
|
return self;
|
||||||
|
@ -155,4 +156,12 @@ public class ApplicationRepresentation {
|
||||||
public void setRedirectUris(List<String> redirectUris) {
|
public void setRedirectUris(List<String> redirectUris) {
|
||||||
this.redirectUris = redirectUris;
|
this.redirectUris = redirectUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getWebOrigins() {
|
||||||
|
return webOrigins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebOrigins(List<String> webOrigins) {
|
||||||
|
this.webOrigins = webOrigins;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
24
examples/js-google/index.html
Normal file
24
examples/js-google/index.html
Normal file
|
@ -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>
|
139
examples/js-google/keycloak.js
Normal file
139
examples/js-google/keycloak.js
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
})();
|
222
examples/js-google/keycloak.js.orig
Normal file
222
examples/js-google/keycloak.js.orig
Normal file
|
@ -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
|
||||||
|
})();
|
13
examples/js-google/kinvey.html
Normal file
13
examples/js-google/kinvey.html
Normal file
|
@ -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>
|
60
examples/js-google/testrealm.json
Executable file
60
examples/js-google/testrealm.json
Executable file
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,120 +1,98 @@
|
||||||
window.keycloak = (function() {
|
window.keycloak = (function () {
|
||||||
var kc = {};
|
var kc = {};
|
||||||
var config = null;
|
var config = {
|
||||||
|
baseUrl: null,
|
||||||
|
clientId: null,
|
||||||
|
clientSecret: null,
|
||||||
|
realm: null
|
||||||
|
};
|
||||||
|
|
||||||
kc.init = function(c) {
|
kc.init = function (c) {
|
||||||
config = c;
|
for (var prop in config) {
|
||||||
|
if (c[prop]) {
|
||||||
|
config[prop] = c[prop];
|
||||||
|
}
|
||||||
|
|
||||||
var token = getTokenFromCode();
|
if (!config[prop]) {
|
||||||
if (token) {
|
throw new Error(prop + 'not defined');
|
||||||
var t = parseToken(token);
|
}
|
||||||
kc.user = t.prn;
|
}
|
||||||
kc.authenticated = true;
|
|
||||||
} else {
|
|
||||||
kc.authenticated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kc.login = function() {
|
var token = getTokenFromCode();
|
||||||
var clientId = encodeURIComponent(config.clientId);
|
if (token) {
|
||||||
var redirectUri = encodeURIComponent(window.location.href);
|
var t = parseToken(token);
|
||||||
var state = encodeURIComponent(createUUID());
|
kc.user = t.prn;
|
||||||
var realm = encodeURIComponent(config.realm);
|
kc.authenticated = true;
|
||||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
|
kc.token = token;
|
||||||
+ '&state=' + state;
|
} else {
|
||||||
window.location.href = url;
|
kc.authenticated = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return kc;
|
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;
|
||||||
|
|
||||||
function parseToken(token) {
|
sessionStorage.state = state;
|
||||||
var t = base64Decode(token.split('.')[1]);
|
|
||||||
return JSON.parse(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTokenFromCode() {
|
window.location.href = url;
|
||||||
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;
|
return kc;
|
||||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
|
|
||||||
|
|
||||||
var http = new XMLHttpRequest();
|
function parseToken(token) {
|
||||||
http.open('POST', url, false);
|
return JSON.parse(atob(token.split('.')[1]));
|
||||||
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
}
|
||||||
|
|
||||||
http.send(params);
|
function getTokenFromCode() {
|
||||||
if (http.status == 200) {
|
var code = getQueryParam('code');
|
||||||
return JSON.parse(http.responseText)['access_token'];
|
var state = getQueryParam('state');
|
||||||
}
|
if (code && state === sessionStorage.state) {
|
||||||
}
|
window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getQueryParam(name) {
|
var clientId = encodeURIComponent(config.clientId);
|
||||||
var params = window.location.search.substring(1).split('&');
|
var clientSecret = encodeURIComponent(config.clientSecret);
|
||||||
for ( var i = 0; i < params.length; i++) {
|
var realm = encodeURIComponent(config.realm);
|
||||||
var p = params[i].split('=');
|
|
||||||
if (decodeURIComponent(p[0]) == name) {
|
|
||||||
return p[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createUUID() {
|
var params = 'code=' + code + '&client_id=' + clientId + '&password=' + clientSecret;
|
||||||
var s = [];
|
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
|
||||||
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 http = new XMLHttpRequest();
|
||||||
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
http.open('POST', url, false);
|
||||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
|
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
ac = 0,
|
|
||||||
dec = "",
|
|
||||||
tmp_arr = [];
|
|
||||||
|
|
||||||
if (!data) {
|
http.send(params);
|
||||||
return data;
|
if (http.status == 200) {
|
||||||
}
|
return JSON.parse(http.responseText)['access_token'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
data += '';
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
function createUUID() {
|
||||||
h1 = b64.indexOf(data.charAt(i++));
|
var s = [];
|
||||||
h2 = b64.indexOf(data.charAt(i++));
|
var hexDigits = '0123456789abcdef';
|
||||||
h3 = b64.indexOf(data.charAt(i++));
|
for (var i = 0; i < 36; i++) {
|
||||||
h4 = b64.indexOf(data.charAt(i++));
|
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||||
|
}
|
||||||
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
|
s[14] = '4';
|
||||||
|
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||||
o1 = bits >> 16 & 0xff;
|
s[8] = s[13] = s[18] = s[23] = '-';
|
||||||
o2 = bits >> 8 & 0xff;
|
var uuid = s.join('');
|
||||||
o3 = bits & 0xff;
|
return uuid;
|
||||||
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
})();
|
})();
|
|
@ -48,6 +48,7 @@
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "http://localhost:8081/app/logout",
|
"adminUrl": "http://localhost:8081/app/logout",
|
||||||
"useRealmMappings": true,
|
"useRealmMappings": true,
|
||||||
|
"webOrigins": [ "http://localhost", "http://localhost:8000", "http://localhost:8080" ],
|
||||||
"credentials": [
|
"credentials": [
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
|
|
|
@ -35,6 +35,14 @@ public interface UserModel {
|
||||||
|
|
||||||
void removeRequiredAction(RequiredAction action);
|
void removeRequiredAction(RequiredAction action);
|
||||||
|
|
||||||
|
Set<String> getWebOrigins();
|
||||||
|
|
||||||
|
void setWebOrigins(Set<String> webOrigins);
|
||||||
|
|
||||||
|
void addWebOrigin(String webOrigin);
|
||||||
|
|
||||||
|
void removeWebOrigin(String webOrigin);
|
||||||
|
|
||||||
Set<String> getRedirectUris();
|
Set<String> getRedirectUris();
|
||||||
|
|
||||||
void setRedirectUris(Set<String> redirectUris);
|
void setRedirectUris(Set<String> redirectUris);
|
||||||
|
|
|
@ -22,6 +22,7 @@ public class UserAdapter implements UserModel {
|
||||||
private static final String REQUIRED_ACTIONS_ATTR = "requiredActions";
|
private static final String REQUIRED_ACTIONS_ATTR = "requiredActions";
|
||||||
|
|
||||||
private static final String REDIRECT_URIS = "redirectUris";
|
private static final String REDIRECT_URIS = "redirectUris";
|
||||||
|
private static final String WEB_ORIGINS = "webOrigins";
|
||||||
|
|
||||||
protected User user;
|
protected User user;
|
||||||
protected IdentityManager idm;
|
protected IdentityManager idm;
|
||||||
|
@ -161,6 +162,26 @@ public class UserAdapter implements UserModel {
|
||||||
removeFromAttributeSet(REDIRECT_URIS, redirectUri);
|
removeFromAttributeSet(REDIRECT_URIS, redirectUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public boolean isTotp() {
|
public boolean isTotp() {
|
||||||
Attribute<Boolean> a = user.getAttribute(KEYCLOAK_TOTP_ATTR);
|
Attribute<Boolean> a = user.getAttribute(KEYCLOAK_TOTP_ATTR);
|
||||||
|
|
|
@ -42,6 +42,11 @@ public class ApplicationManager {
|
||||||
resourceUser.addRedirectUri(redirectUri);
|
resourceUser.addRedirectUri(redirectUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (resourceRep.getWebOrigins() != null) {
|
||||||
|
for (String webOrigin : resourceRep.getWebOrigins()) {
|
||||||
|
resourceUser.addWebOrigin(webOrigin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
realm.grantRole(resourceUser, loginRole);
|
realm.grantRole(resourceUser, loginRole);
|
||||||
|
|
||||||
|
@ -97,6 +102,11 @@ public class ApplicationManager {
|
||||||
if (redirectUris != null) {
|
if (redirectUris != null) {
|
||||||
resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
|
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) {
|
public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
|
||||||
|
@ -113,6 +123,11 @@ public class ApplicationManager {
|
||||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<String> webOrigins = applicationModel.getApplicationUser().getWebOrigins();
|
||||||
|
if (webOrigins != null) {
|
||||||
|
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||||
|
}
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -415,7 +415,8 @@ public class TokenService {
|
||||||
}
|
}
|
||||||
logger.info("accessRequest SUCCESS");
|
logger.info("accessRequest SUCCESS");
|
||||||
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
|
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) {
|
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
|
||||||
|
|
Loading…
Reference in a new issue