[KEYCLOAK-3152] - Keycloak Authorization JS Adapter
This commit is contained in:
parent
8402cedd82
commit
905421a292
3 changed files with 251 additions and 27 deletions
|
@ -58,6 +58,25 @@
|
|||
<goal>minify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>min-authz-js</id>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<charset>utf-8</charset>
|
||||
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
|
||||
<jsSourceDir>.</jsSourceDir>
|
||||
<jsSourceFiles>
|
||||
<jsSourceFile>keycloak-authz.js</jsSourceFile>
|
||||
</jsSourceFiles>
|
||||
|
||||
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
|
||||
<jsTargetDir>.</jsTargetDir>
|
||||
<jsFinalFile>keycloak-authz.js</jsFinalFile>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>minify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
170
adapters/oidc/js/src/main/resources/keycloak-authz.js
Normal file
170
adapters/oidc/js/src/main/resources/keycloak-authz.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
(function( window, undefined ) {
|
||||
|
||||
var KeycloakAuthorization = function (keycloak) {
|
||||
var _instance = this;
|
||||
this.rpt = null;
|
||||
|
||||
this.init = function () {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma-configuration');
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
if (request.status == 200) {
|
||||
_instance.config = JSON.parse(request.responseText);
|
||||
} else {
|
||||
console.error('Could not obtain configuration from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.send(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method enables client applications to better integrate with resource servers protected by a Keycloak
|
||||
* policy enforcer.
|
||||
*
|
||||
* In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
|
||||
* necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
|
||||
* depending on how the policy enforcer at the resource server was configured.
|
||||
*/
|
||||
this.authorize = function (wwwAuthenticateHeader) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
if (wwwAuthenticateHeader.startsWith('UMA')) {
|
||||
var params = wwwAuthenticateHeader.split(',');
|
||||
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var param = params[i].split('=');
|
||||
|
||||
if (param[0] == 'ticket') {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('POST', _instance.config.rpt_endpoint, true);
|
||||
request.setRequestHeader('Content-Type', 'application/json')
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var ticket = param[1].substring(1, param[1].length - 1).trim();
|
||||
|
||||
request.send(JSON.stringify(
|
||||
{
|
||||
ticket: ticket,
|
||||
rpt: _instance.rpt
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if (wwwAuthenticateHeader.startsWith('KC_ETT')) {
|
||||
var params = wwwAuthenticateHeader.substring('KC_ETT'.length).trim().split(',');
|
||||
var clientId = null;
|
||||
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var param = params[i].split('=');
|
||||
|
||||
if (param[0] == 'realm') {
|
||||
clientId = param[1].substring(1, param[1].length - 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
_instance.entitlement(clientId).then(onGrant, onDeny, onError);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
|
||||
*/
|
||||
this.entitlement = function (resourceSeververId) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.send(null);
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.init(this);
|
||||
};
|
||||
|
||||
if ( typeof module === "object" && module && typeof module.exports === "object" ) {
|
||||
module.exports = KeycloakAuthorization;
|
||||
} else {
|
||||
window.KeycloakAuthorization = KeycloakAuthorization;
|
||||
|
||||
if ( typeof define === "function" && define.amd ) {
|
||||
define( "keycloak-authorization", [], function () { return KeycloakAuthorization; } );
|
||||
}
|
||||
}
|
||||
})( window );
|
|
@ -44,35 +44,82 @@ public class JsResource {
|
|||
@GET
|
||||
@Path("/keycloak.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getJs() {
|
||||
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js");
|
||||
if (inputStream != null) {
|
||||
CacheControl cacheControl = new CacheControl();
|
||||
cacheControl.setNoTransform(false);
|
||||
cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
|
||||
|
||||
return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
|
||||
} else {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
public Response getKeycloakJs() {
|
||||
return getJs("keycloak.js");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{version}/keycloak.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getJsWithVersion(@PathParam("version") String version) {
|
||||
public Response getKeycloakJsWithVersion(@PathParam("version") String version) {
|
||||
if (!version.equals(Version.RESOURCES_VERSION)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return getJs();
|
||||
return getKeycloakJs();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/keycloak.min.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getMinJs() {
|
||||
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.min.js");
|
||||
public Response getKeycloakMinJs() {
|
||||
return getJs("keycloak.min.js");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{version}/keycloak.min.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getKeycloakMinJsWithVersion(@PathParam("version") String version) {
|
||||
if (!version.equals(Version.RESOURCES_VERSION)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return getKeycloakMinJs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get keycloak-authz.js file for javascript clients
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("/keycloak-authz.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getKeycloakAuthzJs() {
|
||||
return getJs("keycloak-authz.js");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{version}/keycloak-authz.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getKeycloakAuthzJsWithVersion(@PathParam("version") String version) {
|
||||
if (!version.equals(Version.RESOURCES_VERSION)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return getKeycloakAuthzJs();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/keycloak-authz.min.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getKeycloakAuthzMinJs() {
|
||||
return getJs("keycloak-authz.min.js");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{version}/keycloak-authz.min.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getKeycloakAuthzMinJsWithVersion(@PathParam("version") String version) {
|
||||
if (!version.equals(Version.RESOURCES_VERSION)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return getKeycloakAuthzMinJs();
|
||||
}
|
||||
|
||||
private Response getJs(String name) {
|
||||
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(name);
|
||||
if (inputStream != null) {
|
||||
CacheControl cacheControl = new CacheControl();
|
||||
cacheControl.setNoTransform(false);
|
||||
|
@ -83,16 +130,4 @@ public class JsResource {
|
|||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{version}/keycloak.min.js")
|
||||
@Produces("text/javascript")
|
||||
public Response getMinJsWithVersion(@PathParam("version") String version) {
|
||||
if (!version.equals(Version.RESOURCES_VERSION)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return getMinJs();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue