Updates to keycloak.js
This commit is contained in:
parent
331ab71427
commit
2d5e6520db
8 changed files with 514 additions and 243 deletions
73
examples/js-console/example-realm.json
Executable file
73
examples/js-console/example-realm.json
Executable file
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"realm": "example",
|
||||
"enabled": true,
|
||||
"sslNotRequired": true,
|
||||
"registrationAllowed": 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" ],
|
||||
"users" : [
|
||||
{
|
||||
"username" : "user",
|
||||
"enabled": true,
|
||||
"email" : "sample-user@example",
|
||||
"firstName": "Sample",
|
||||
"lastName": "User",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"roles" : {
|
||||
"realm" : [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator privileges"
|
||||
}
|
||||
]
|
||||
},
|
||||
"roleMappings": [
|
||||
{
|
||||
"username": "user",
|
||||
"roles": ["user"]
|
||||
}
|
||||
],
|
||||
"scopeMappings": [
|
||||
{
|
||||
"client": "js-console",
|
||||
"roles": ["user"]
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
{
|
||||
"name": "js-console",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"baseUrl": "http://localhost:8080/js-console",
|
||||
"redirectUris": [
|
||||
"http://localhost:8080/js-console/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"applicationRoleMappings": {
|
||||
"account": [
|
||||
{
|
||||
"username": "user",
|
||||
"roles": ["view-profile", "manage-account"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"applicationScopeMappings": {
|
||||
"account": [
|
||||
{
|
||||
"client": "js-console",
|
||||
"roles": ["view-profile"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
42
examples/js-console/pom.xml
Executable file
42
examples/js-console/pom.xml
Executable file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-1-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.keycloak.example.demo</groupId>
|
||||
<artifactId>js-console</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>JS Console</name>
|
||||
<description/>
|
||||
|
||||
<build>
|
||||
<finalName>js-console</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jboss.as.plugins</groupId>
|
||||
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||
<version>7.4.Final</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
97
examples/js-console/src/main/webapp/index.html
Normal file
97
examples/js-console/src/main/webapp/index.html
Normal file
|
@ -0,0 +1,97 @@
|
|||
<html>
|
||||
<head>
|
||||
<script src="http://localhost:8080/auth/js/keycloak.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div>
|
||||
<button onclick="keycloak.login()">Login</button>
|
||||
<button onclick="keycloak.logout()">Logout</button>
|
||||
<button onclick="refreshToken()">Refresh Token</button>
|
||||
<button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
|
||||
<button onclick="loadProfile()">Get Profile</button>
|
||||
<button onclick="output(keycloak.tokenParsed)">Show Token</button>
|
||||
<button onclick="output(keycloak.refreshTokenParsed)">Show Refresh Token</button>
|
||||
<button onclick="showExpires()">Show Expires</button>
|
||||
<button onclick="output(keycloak.idToken)">Show ID Token</button>
|
||||
<button onclick="output(keycloak)">Show Details</button>
|
||||
<button onclick="output(keycloak.createLoginUrl())">Show Login URL</button>
|
||||
<button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
|
||||
</div>
|
||||
|
||||
<h2>Result</h2>
|
||||
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
|
||||
|
||||
<h2>Events</h2>
|
||||
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="events"></pre>
|
||||
|
||||
|
||||
<script>
|
||||
function loadProfile() {
|
||||
keycloak.loadUserProfile().success(function(profile) {
|
||||
output(profile);
|
||||
}).error(function() {
|
||||
output('Failed to load profile');
|
||||
});
|
||||
}
|
||||
|
||||
function refreshToken(minValidity) {
|
||||
keycloak.refreshAccessToken(minValidity).success(function(refreshed) {
|
||||
if (refreshed) {
|
||||
output(keycloak.tokenParsed);
|
||||
} else {
|
||||
output('Token not refreshed, valid for ' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds');
|
||||
}
|
||||
}).error(function() {
|
||||
output('Failed to refresh token');
|
||||
});
|
||||
}
|
||||
|
||||
function showExpires() {
|
||||
var o = 'Token Expires:\t\t' + new Date(keycloak.tokenParsed.exp * 1000).toLocaleString() + '\n';
|
||||
o += 'Token Expires in:\t' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds\n';
|
||||
|
||||
o += 'Refresh Token Expires:\t' + new Date(keycloak.refreshTokenParsed.exp * 1000).toLocaleString() + '\n';
|
||||
o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp - new Date().getTime() / 1000) + ' seconds';
|
||||
output(o);
|
||||
}
|
||||
|
||||
function output(data) {
|
||||
if (typeof data === 'object') {
|
||||
data = JSON.stringify(data, null, ' ');
|
||||
}
|
||||
document.getElementById('output').innerText = data;
|
||||
}
|
||||
|
||||
function event(event) {
|
||||
var e = document.getElementById('events').innerText;
|
||||
document.getElementById('events').innerText = new Date().toLocaleString() + "\t" + event + "\n" + e;
|
||||
}
|
||||
|
||||
var keycloak = Keycloak();
|
||||
|
||||
keycloak.onAuthSuccess = function () {
|
||||
event('Auth Success');
|
||||
};
|
||||
|
||||
keycloak.onAuthError = function () {
|
||||
event('Auth Error');
|
||||
};
|
||||
|
||||
keycloak.onAuthRefreshSuccess = function () {
|
||||
event('Auth Refresh Success');
|
||||
};
|
||||
|
||||
keycloak.onAuthRefreshError = function () {
|
||||
event('Auth Refresh Error');
|
||||
};
|
||||
|
||||
keycloak.init().success(function(authenticated) {
|
||||
output('Init Success (' + (authenticated ? 'Authenticated' : 'Not Authenticated') + ')');
|
||||
}).error(function() {
|
||||
output('Init Error');
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
8
examples/js-console/src/main/webapp/keycloak.json
Normal file
8
examples/js-console/src/main/webapp/keycloak.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"realm" : "example",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://localhost:8080/auth",
|
||||
"ssl-not-required" : true,
|
||||
"resource" : "js-console",
|
||||
"public-client" : true
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"id": "test",
|
||||
"realm": "test",
|
||||
"enabled": true,
|
||||
"sslNotRequired": 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" ],
|
||||
"users" : [
|
||||
{
|
||||
"username" : "test",
|
||||
"enabled": true,
|
||||
"email" : "test-user@localhost",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "test" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
{
|
||||
"name": "test",
|
||||
"enabled": true,
|
||||
"secret": "password"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,58 +1,108 @@
|
|||
var Keycloak = function (options) {
|
||||
options = options || {};
|
||||
|
||||
var Keycloak = function (config) {
|
||||
if (!(this instanceof Keycloak)) {
|
||||
return new Keycloak(options);
|
||||
return new Keycloak(config);
|
||||
}
|
||||
|
||||
var kc = this;
|
||||
kc.authenticated = false;
|
||||
|
||||
if (!options.url) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (scripts[i].src.match(/.*keycloak\.js/)) {
|
||||
options.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/auth/js/keycloak.js'));
|
||||
break;
|
||||
var configPromise = createPromise();
|
||||
configPromise.name = 'config';
|
||||
|
||||
if (!config) {
|
||||
loadConfig('keycloak.json', configPromise);
|
||||
} else if (typeof config === 'string') {
|
||||
loadConfig(config, configPromise);
|
||||
} else {
|
||||
if (!config['url']) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (scripts[i].src.match(/.*keycloak\.js/)) {
|
||||
config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.url) {
|
||||
throw 'url missing';
|
||||
}
|
||||
|
||||
if (!options.realm) {
|
||||
throw 'realm missing';
|
||||
}
|
||||
|
||||
if (!options.clientId) {
|
||||
throw 'clientId missing';
|
||||
}
|
||||
|
||||
kc.init = function (successCallback, errorCallback) {
|
||||
if (window.oauth.callback) {
|
||||
processCallback(successCallback, errorCallback);
|
||||
} else if (options.token) {
|
||||
kc.setToken(options.token, successCallback);
|
||||
} else if (options.onload) {
|
||||
switch (options.onload) {
|
||||
case 'login-required' :
|
||||
window.location = kc.createLoginUrl(true);
|
||||
break;
|
||||
case 'check-sso' :
|
||||
window.location = kc.createLoginUrl(false);
|
||||
break;
|
||||
}
|
||||
if (!config.realm) {
|
||||
throw 'realm missing';
|
||||
}
|
||||
|
||||
if (!config.clientId) {
|
||||
throw 'clientId missing';
|
||||
}
|
||||
|
||||
kc.authServerUrl = config.url;
|
||||
kc.realm = config.realm;
|
||||
kc.clientId = config.clientId;
|
||||
|
||||
configPromise.setSuccess();
|
||||
}
|
||||
|
||||
kc.login = function () {
|
||||
window.location.href = kc.createLoginUrl(true);
|
||||
kc.init = function (init) {
|
||||
var promise = createPromise();
|
||||
var callback = parseCallback(window.location.href);
|
||||
|
||||
function processInit() {
|
||||
if (callback) {
|
||||
window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (callback.fragment ? '#' + callback.fragment : ''));
|
||||
processCallback(callback, promise);
|
||||
return;
|
||||
} else if (init) {
|
||||
if (init.code || init.error) {
|
||||
processCallback(init, promise);
|
||||
return;
|
||||
} else if (init.token || init.refreshToken) {
|
||||
setToken(init.token, init.refreshToken);
|
||||
} else if (init == 'login-required') {
|
||||
kc.login();
|
||||
return;
|
||||
} else if (init == 'check-sso') {
|
||||
window.location = kc.createLoginUrl() + '&prompt=none';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
promise.setSuccess(false);
|
||||
}
|
||||
|
||||
configPromise.promise.success(processInit);
|
||||
|
||||
return promise.promise;
|
||||
}
|
||||
|
||||
kc.logout = function () {
|
||||
kc.setToken(undefined);
|
||||
window.location.href = kc.createLogoutUrl();
|
||||
kc.login = function (redirectUri) {
|
||||
window.location.href = kc.createLoginUrl(redirectUri);
|
||||
}
|
||||
|
||||
kc.createLoginUrl = function(redirectUri) {
|
||||
var state = createUUID();
|
||||
|
||||
sessionStorage.oauthState = state;
|
||||
var url = getRealmUrl()
|
||||
+ '/tokens/login'
|
||||
+ '?client_id=' + encodeURIComponent(kc.clientId)
|
||||
+ '&redirect_uri=' + getEncodedRedirectUri(redirectUri)
|
||||
+ '&state=' + encodeURIComponent(state)
|
||||
+ '&response_type=code';
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
kc.logout = function(redirectUri) {
|
||||
setToken(null, null);
|
||||
window.location.href = kc.createLogoutUrl(redirectUri);
|
||||
}
|
||||
|
||||
kc.clearToken = function() {
|
||||
setToken(null, null);
|
||||
}
|
||||
|
||||
kc.createLogoutUrl = function(redirectUri) {
|
||||
var url = getRealmUrl()
|
||||
+ '/tokens/logout'
|
||||
+ '?redirect_uri=' + getEncodedRedirectUri(redirectUri);
|
||||
return url;
|
||||
}
|
||||
|
||||
kc.hasRealmRole = function (role) {
|
||||
|
@ -60,122 +110,131 @@ var Keycloak = function (options) {
|
|||
return access && access.roles.indexOf(role) >= 0 || false;
|
||||
}
|
||||
|
||||
kc.hasResourceRole = function (role, resource) {
|
||||
kc.hasResourceRole = function(role, resource) {
|
||||
if (!kc.resourceAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var access = kc.resourceAccess[resource || options.clientId];
|
||||
var access = kc.resourceAccess[resource || kc.clientId];
|
||||
return access && access.roles.indexOf(role) >= 0 || false;
|
||||
}
|
||||
|
||||
kc.loadUserProfile = function (success, error) {
|
||||
var url = kc.getRealmUrl() + '/account';
|
||||
kc.loadUserProfile = function() {
|
||||
var url = getRealmUrl() + '/account';
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
req.setRequestHeader('Authorization', 'bearer ' + kc.token);
|
||||
|
||||
var promise = createPromise();
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
kc.profile = JSON.parse(req.responseText);
|
||||
success && success(kc.profile)
|
||||
promise.setSuccess(kc.profile);
|
||||
} else {
|
||||
var response = { status: req.status, statusText: req.status };
|
||||
if (req.responseText) {
|
||||
response.data = JSON.parse(req.responseText);
|
||||
}
|
||||
error && error(response);
|
||||
promise.setError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.send();
|
||||
|
||||
return promise.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks to make sure token is valid. If it is, it calls successCallback with no parameters.
|
||||
* If it isn't valid, it tries to refresh the access token. On successful refresh, it calls successCallback.
|
||||
*
|
||||
* @param successCallback
|
||||
* @param errorCallback
|
||||
*/
|
||||
kc.onValidAccessToken = function(successCallback, errorCallback) {
|
||||
if (!kc.tokenParsed) {
|
||||
console.log('no token');
|
||||
errorCallback();
|
||||
return;
|
||||
kc.refreshAccessToken = function(minValidity) {
|
||||
if (!kc.tokenParsed || !kc.refreshToken) {
|
||||
throw 'Not authenticated';
|
||||
}
|
||||
var currTime = new Date().getTime() / 1000;
|
||||
if (currTime > kc.tokenParsed['exp']) {
|
||||
if (!kc.refreshToken) {
|
||||
console.log('no refresh token');
|
||||
errorCallback();
|
||||
return;
|
||||
|
||||
var promise = createPromise();
|
||||
|
||||
if (minValidity) {
|
||||
var expiresIn = kc.tokenParsed['exp'] - (new Date().getTime() / 1000);
|
||||
if (expiresIn > minValidity) {
|
||||
promise.setSuccess(false);
|
||||
return promise.promise;
|
||||
}
|
||||
console.log('calling refresh');
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||
var url = kc.getRealmUrl() + '/tokens/refresh';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true, options.clientId, options.clientSecret);
|
||||
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
console.log('Refresh Success');
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
kc.refreshToken = tokenResponse['refresh_token'];
|
||||
kc.setToken(tokenResponse['access_token'], successCallback);
|
||||
} else {
|
||||
console.log('error on refresh HTTP invoke: ' + req.status);
|
||||
errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
|
||||
}
|
||||
}
|
||||
};
|
||||
req.send(params);
|
||||
} else {
|
||||
console.log('Token is still valid');
|
||||
successCallback();
|
||||
}
|
||||
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||
var url = getRealmUrl() + '/tokens/refresh';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true);
|
||||
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
if (kc.clientId && kc.clientSecret) {
|
||||
req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
|
||||
} else {
|
||||
params += '&client_id=' + encodeURIComponent(kc.clientId);
|
||||
}
|
||||
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
|
||||
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
|
||||
promise.setSuccess(true);
|
||||
} else {
|
||||
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
||||
promise.setError();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
req.send(params);
|
||||
|
||||
return promise.promise;
|
||||
}
|
||||
|
||||
kc.getRealmUrl = function() {
|
||||
return options.url + '/auth/rest/realms/' + encodeURIComponent(options.realm);
|
||||
kc.processCallback = function(url) {
|
||||
var callback = parseCallback(url);
|
||||
if (callback) {
|
||||
var promise = createPromise();
|
||||
processCallback(callback, promise);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
function processCallback(successCallback, errorCallback) {
|
||||
var code = window.oauth.code;
|
||||
var error = window.oauth.error;
|
||||
var prompt = window.oauth.prompt;
|
||||
function getRealmUrl() {
|
||||
return kc.authServerUrl + '/rest/realms/' + encodeURIComponent(kc.realm);
|
||||
}
|
||||
|
||||
function processCallback(oauth, promise) {
|
||||
var code = oauth.code;
|
||||
var error = oauth.error;
|
||||
var prompt = oauth.prompt;
|
||||
|
||||
if (code) {
|
||||
var params = 'code=' + code;
|
||||
var url = kc.getRealmUrl() + '/tokens/access/codes';
|
||||
var url = getRealmUrl() + '/tokens/access/codes';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true);
|
||||
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
if (options.clientId && options.clientSecret) {
|
||||
req.setRequestHeader('Authorization', 'Basic ' + btoa(options.clientId + ':' + options.clientSecret));
|
||||
if (kc.clientId && kc.clientSecret) {
|
||||
req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
|
||||
} else {
|
||||
params += '&client_id=' + encodeURIComponent(options.clientId);
|
||||
params += '&client_id=' + encodeURIComponent(kc.clientId);
|
||||
}
|
||||
|
||||
req.withCredentials = true;
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
kc.refreshToken = tokenResponse['refresh_token'];
|
||||
kc.setToken(tokenResponse['access_token'], successCallback);
|
||||
setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
|
||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
||||
promise.setSuccess(true);
|
||||
} else {
|
||||
errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
|
||||
kc.onAuthError && kc.onAuthError();
|
||||
promise.setError();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -183,16 +242,38 @@ var Keycloak = function (options) {
|
|||
req.send(params);
|
||||
} else if (error) {
|
||||
if (prompt != 'none') {
|
||||
setTimeout(function() {
|
||||
errorCallback && errorCallback({ authenticated: false, error: error })
|
||||
}, 0);
|
||||
kc.onAuthError && kc.onAuthError();
|
||||
promise.setError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kc.setToken = function(token, successCallback) {
|
||||
function loadConfig(url, configPromise) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
var config = JSON.parse(req.responseText);
|
||||
|
||||
kc.authServerUrl = config['auth-server-url'];
|
||||
kc.realm = config['realm'];
|
||||
kc.clientId = config['resource'];
|
||||
|
||||
configPromise.setSuccess();
|
||||
} else {
|
||||
configPromise.setError();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
req.send();
|
||||
}
|
||||
|
||||
function setToken(token, refreshToken) {
|
||||
if (token) {
|
||||
window.oauth.token = token;
|
||||
kc.token = token;
|
||||
kc.tokenParsed = JSON.parse(atob(token.split('.')[1]));
|
||||
kc.authenticated = true;
|
||||
|
@ -209,45 +290,32 @@ var Keycloak = function (options) {
|
|||
kc.idToken[n] = kc.tokenParsed[n];
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
successCallback && successCallback({ authenticated: kc.authenticated, subject: kc.subject });
|
||||
}, 0);
|
||||
} else {
|
||||
delete window.oauth.token;
|
||||
delete kc.token;
|
||||
delete kc.tokenParsed;
|
||||
delete kc.subject;
|
||||
delete kc.realmAccess;
|
||||
delete kc.resourceAccess;
|
||||
delete kc.idToken;
|
||||
|
||||
kc.authenticated = false;
|
||||
}
|
||||
|
||||
if (refreshToken) {
|
||||
kc.refreshToken = refreshToken;
|
||||
kc.refreshTokenParsed = JSON.parse(atob(refreshToken.split('.')[1]));
|
||||
} else {
|
||||
delete kc.refreshToken;
|
||||
delete kc.refreshTokenParsed;
|
||||
}
|
||||
}
|
||||
|
||||
kc.createLoginUrl = function(prompt) {
|
||||
var state = createUUID();
|
||||
|
||||
sessionStorage.oauthState = state;
|
||||
var url = kc.getRealmUrl()
|
||||
+ '/tokens/login'
|
||||
+ '?client_id=' + encodeURIComponent(options.clientId)
|
||||
+ '&redirect_uri=' + getEncodedRedirectUri()
|
||||
+ '&state=' + encodeURIComponent(state)
|
||||
+ '&response_type=code';
|
||||
|
||||
if (prompt == false) {
|
||||
url += '&prompt=none';
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
kc.createLogoutUrl = function() {
|
||||
var url = kc.getRealmUrl()
|
||||
+ '/tokens/logout'
|
||||
+ '?redirect_uri=' + getEncodedRedirectUri();
|
||||
return url;
|
||||
}
|
||||
|
||||
function getEncodedRedirectUri() {
|
||||
function getEncodedRedirectUri(redirectUri) {
|
||||
var url;
|
||||
if (options.redirectUri) {
|
||||
url = options.redirectUri;
|
||||
if (redirectUri) {
|
||||
url = redirectUri;
|
||||
} else if (kc.redirectUri) {
|
||||
url = kc.redirectUri;
|
||||
} else {
|
||||
url = (location.protocol + '//' + location.hostname + (location.port && (':' + location.port)) + location.pathname);
|
||||
if (location.hash) {
|
||||
|
@ -269,7 +337,81 @@ var Keycloak = function (options) {
|
|||
var uuid = s.join('');
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
function parseCallback(url) {
|
||||
|
||||
if (url.indexOf('?') != -1) {
|
||||
var oauth = {};
|
||||
|
||||
var params = url.split('?')[1].split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
switch (decodeURIComponent(p[0])) {
|
||||
case 'code':
|
||||
oauth.code = p[1];
|
||||
break;
|
||||
case 'error':
|
||||
oauth.error = p[1];
|
||||
break;
|
||||
case 'state':
|
||||
oauth.state = decodeURIComponent(p[1]);
|
||||
break;
|
||||
case 'redirect_fragment':
|
||||
oauth.fragment = decodeURIComponent(p[1]);
|
||||
break;
|
||||
case 'prompt':
|
||||
oauth.prompt = p[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oauth.state && oauth.state == sessionStorage.oauthState) {
|
||||
delete sessionStorage.oauthState;
|
||||
return oauth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createPromise() {
|
||||
var p = {
|
||||
setSuccess: function(result) {
|
||||
p.success = true;
|
||||
p.result = result;
|
||||
if (p.successCallback) {
|
||||
p.successCallback(result);
|
||||
}
|
||||
},
|
||||
|
||||
setError: function(result) {
|
||||
p.error = true;
|
||||
p.result = result;
|
||||
if (p.errorCallback) {
|
||||
p.errorCallback(result);
|
||||
}
|
||||
},
|
||||
|
||||
promise: {
|
||||
success: function(callback) {
|
||||
if (p.success) {
|
||||
callback(p.result);
|
||||
} else if (!p.error) {
|
||||
p.successCallback = callback;
|
||||
}
|
||||
return p.promise;
|
||||
},
|
||||
error: function(callback) {
|
||||
if (p.error) {
|
||||
callback(p.result);
|
||||
} else if (!p.success) {
|
||||
p.errorCallback = callback;
|
||||
}
|
||||
return p.promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
var idTokenProperties = [
|
||||
"name",
|
||||
"given_name",
|
||||
|
@ -298,45 +440,4 @@ var Keycloak = function (options) {
|
|||
"country",
|
||||
"claims_locales"
|
||||
]
|
||||
}
|
||||
|
||||
window.oauth = (function () {
|
||||
var oauth = {};
|
||||
|
||||
var params = window.location.search.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
switch (decodeURIComponent(p[0])) {
|
||||
case 'code':
|
||||
oauth.code = p[1];
|
||||
break;
|
||||
case 'error':
|
||||
oauth.error = p[1];
|
||||
break;
|
||||
case 'state':
|
||||
oauth.state = decodeURIComponent(p[1]);
|
||||
break;
|
||||
case 'redirect_fragment':
|
||||
oauth.fragment = decodeURIComponent(p[1]);
|
||||
break;
|
||||
case 'prompt':
|
||||
oauth.prompt = p[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oauth.state && oauth.state == sessionStorage.oauthState) {
|
||||
oauth.callback = true;
|
||||
delete sessionStorage.oauthState;
|
||||
} else {
|
||||
oauth.callback = false;
|
||||
}
|
||||
|
||||
if (oauth.callback) {
|
||||
window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (oauth.fragment ? '#' + oauth.fragment : ''));
|
||||
} else if (oauth.fragment) {
|
||||
window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (oauth.fragment ? '#' + oauth.fragment : ''));
|
||||
}
|
||||
|
||||
return oauth;
|
||||
}());
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<script src="http://192.168.0.16/js/keycloak.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="keycloak.login()">Login</button>
|
||||
|
||||
<script>
|
||||
var keycloak = Keycloak({ realm: 'test', clientId: 'test', clientSecret: 'password' });
|
||||
|
||||
keycloak.init(function () {
|
||||
console.debug('Token: ' + keycloak.tokenParsed);
|
||||
console.debug('Realm access: ' + keycloak.realmAccess);
|
||||
console.debug('Resource access: ' + keycloak.resourceAccess);
|
||||
|
||||
keycloak.loadUserProfile(function (profile) {
|
||||
console.debug(profile);
|
||||
}, function (error) {
|
||||
console.debug(error);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -37,8 +37,9 @@ public class KeycloakServerApplication extends KeycloakApplication {
|
|||
try {
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
||||
if (rep.getId() == null) {
|
||||
throw new RuntimeException("Realm id not specified");
|
||||
if (rep.getId() != null && manager.getRealm(rep.getId()) != null) {
|
||||
log.info("Not importing realm " + rep.getRealm() + " realm already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager.getRealmByName(rep.getRealm()) != null) {
|
||||
|
|
Loading…
Reference in a new issue