Merge pull request #261 from stianst/master

Fixes to cors for js. Improvements to login form for small screens. Fix ng-disabled with kc-read-only forms
This commit is contained in:
Stian Thorgersen 2014-03-04 15:28:51 +00:00
commit df61879fb1
5 changed files with 64 additions and 31 deletions

View file

@ -668,12 +668,13 @@ module.directive('onoffswitch', function() {
name: '@', name: '@',
id: '@', id: '@',
ngModel: '=', ngModel: '=',
ngDisabled: '=',
kcOnText: '@onText', kcOnText: '@onText',
kcOffText: '@offText' kcOffText: '@offText'
}, },
// TODO - The same code acts differently when put into the templateURL. Find why and move the code there. // TODO - The same code acts differently when put into the templateURL. Find why and move the code there.
//templateUrl: "templates/kc-switch.html", //templateUrl: "templates/kc-switch.html",
template: "<span><div class='onoffswitch' tabindex='0'><input type='checkbox' ng-model='ngModel' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'><label for='{{id}}' class='onoffswitch-label'><span class='onoffswitch-inner'><span class='onoffswitch-active'>{{kcOnText}}</span><span class='onoffswitch-inactive'>{{kcOffText}}</span></span><span class='onoffswitch-switch'></span></label></div></span>", template: "<span><div class='onoffswitch' tabindex='0'><input type='checkbox' ng-model='ngModel' ng-disabled='ngDisabled' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'><label for='{{id}}' class='onoffswitch-label'><span class='onoffswitch-inner'><span class='onoffswitch-active'>{{kcOnText}}</span><span class='onoffswitch-inactive'>{{kcOffText}}</span></span><span class='onoffswitch-switch'></span></label></div></span>",
compile: function(element, attrs) { compile: function(element, attrs) {
/* /*
We don't want to propagate basic attributes to the root element of directive. Id should be passed to the We don't want to propagate basic attributes to the root element of directive. Id should be passed to the
@ -834,20 +835,38 @@ module.directive('kcDropdown', function ($compile, Notifications) {
}); });
module.directive('kcReadOnly', function() { module.directive('kcReadOnly', function() {
var disabled = {};
var d = { var d = {
replace : false, replace : false,
link : function(scope, element, attrs) { link : function(scope, element, attrs) {
scope.$watch(attrs.kcReadOnly, function(readOnly, oldValue) { var disable = function(i, e) {
if (!e.disabled) {
disabled[e.tagName + i] = true;
e.disabled = true;
}
}
var enable = function(i, e) {
if (disabled[e.tagName + i]) {
e.disabled = false;
delete disabled[i];
}
}
scope.$watch(attrs.kcReadOnly, function(readOnly) {
if (readOnly) { if (readOnly) {
element.find('input').attr('disabled', 'disabled'); console.debug('readonly');
element.find('button').attr('disabled', 'disabled'); element.find('input').each(disable);
element.find('select').attr('disabled', 'disabled'); element.find('button').each(disable);
element.find('textarea').attr('disabled', 'disabled'); element.find('select').each(disable);
element.find('textarea').each(disable);
} else { } else {
element.find('input').removeAttr('disabled'); element.find('input').each(enable);
element.find('button').removeAttr('disabled'); element.find('input').each(enable);
element.find('select').removeAttr('disabled'); element.find('button').each(enable);
element.find('textarea').removeAttr('disabled'); element.find('select').each(enable);
element.find('textarea').each(enable);
} }
}); });
} }

View file

@ -47,7 +47,6 @@
#kc-login { #kc-login {
float: right; float: right;
margin-left: 10px; margin-left: 10px;
margin-bottom: 10px;
} }
#kc-feedback-wrapper { #kc-feedback-wrapper {
@ -210,19 +209,19 @@ ol#kc-totp-settings li:first-of-type {
height: 37px; height: 37px;
margin: 20px; margin: 15px;
} }
#kc-header { #kc-header {
padding-left: 40px; padding-left: 15px;
padding-right: 40px; padding-right: 15px;
white-space: normal; white-space: normal;
float: none; float: none;
} }
#kc-feedback { #kc-feedback {
padding-left: 40px; padding-left: 15px;
padding-right: 40px; padding-right: 15px;
float: none; float: none;
} }
@ -232,21 +231,26 @@ ol#kc-totp-settings li:first-of-type {
} }
#kc-form { #kc-form {
padding-left: 40px; padding-left: 15px;
padding-right: 40px; padding-right: 15px;
float: none; float: none;
} }
#kc-info-wrapper { #kc-info-wrapper {
border-top: 1px solid rgba(255, 255, 255, 0.1); border-top: 1px solid rgba(255, 255, 255, 0.1);
margin-top: 20px; margin-top: 15px;
padding-top: 20px; padding-top: 15px;
padding-left: 20px; padding-left: 0px;
padding-right: 40px; padding-right: 15px;
} }
#kc-social-providers li { #kc-social-providers li {
display: inline-block; display: inline-block;
margin-right: 5px; margin-right: 5px;
} }
.login-pf .container {
padding-top: 15px;
padding-bottom: 15px;
}
} }

View file

@ -19,7 +19,7 @@ kcLabelClass=control-label
kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-4 col-lg-3 kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-4 col-lg-3
kcInputClass=form-control kcInputClass=form-control
kcInputWrapperClass=col-xs-12 col-sm-12 col-md-8 col-lg-9 kcInputWrapperClass=col-xs-12 col-sm-12 col-md-8 col-lg-9
kcFormOptionsClass=col-xs-5 col-sm-5 col-md-offset-4 col-md-4 col-lg-offset-3 col-lg-5 kcFormOptionsClass=col-xs-4 col-sm-5 col-md-offset-4 col-md-4 col-lg-offset-3 col-lg-5
kcFormButtonsClass=col-xs-7 col-sm-7 col-md-4 col-lg-4 submit kcFormButtonsClass=col-xs-8 col-sm-7 col-md-4 col-lg-4 submit
kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-6 details kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-6 details

View file

@ -38,9 +38,9 @@ var Keycloak = function (options) {
delete sessionStorage.oauthToken; delete sessionStorage.oauthToken;
processCallback(successCallback, errorCallback); processCallback(successCallback, errorCallback);
} else if (options.token) { } else if (options.token) {
setToken(options.token, successCallback); kc.setToken(options.token, successCallback);
} else if (sessionStorage.oauthToken) { } else if (sessionStorage.oauthToken) {
setToken(sessionStorage.oauthToken, successCallback); kc.setToken(sessionStorage.oauthToken, successCallback);
} else if (options.onload) { } else if (options.onload) {
switch (options.onload) { switch (options.onload) {
case 'login-required' : case 'login-required' :
@ -58,7 +58,7 @@ var Keycloak = function (options) {
} }
kc.logout = function () { kc.logout = function () {
setToken(undefined); kc.setToken(undefined);
window.location.href = kc.createLogoutUrl(); window.location.href = kc.createLogoutUrl();
} }
@ -164,8 +164,10 @@ var Keycloak = function (options) {
var url = kc.getRealmUrl() + '/tokens/access/codes'; var url = kc.getRealmUrl() + '/tokens/access/codes';
var req = new XMLHttpRequest(); var req = new XMLHttpRequest();
req.open('POST', url, true, options.clientId, options.clientSecret); req.open('POST', url, true);
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.setRequestHeader('Authorization', 'Basic ' + btoa(options.clientId + ':' + options.clientSecret));
req.withCredentials = true;
req.onreadystatechange = function () { req.onreadystatechange = function () {
if (req.readyState == 4) { if (req.readyState == 4) {
@ -197,12 +199,12 @@ var Keycloak = function (options) {
kc.tokenParsed = JSON.parse(atob(token.split('.')[1])); kc.tokenParsed = JSON.parse(atob(token.split('.')[1]));
kc.authenticated = true; kc.authenticated = true;
kc.username = kc.tokenParsed.sub; kc.subject = kc.tokenParsed.sub;
kc.realmAccess = kc.tokenParsed.realm_access; kc.realmAccess = kc.tokenParsed.realm_access;
kc.resourceAccess = kc.tokenParsed.resource_access; kc.resourceAccess = kc.tokenParsed.resource_access;
setTimeout(function() { setTimeout(function() {
successCallback && successCallback({ authenticated: kc.authenticated, username: kc.username }); successCallback && successCallback({ authenticated: kc.authenticated, subject: kc.subject });
}, 0); }, 0);
} else { } else {
delete sessionStorage.oauthToken; delete sessionStorage.oauthToken;

View file

@ -38,6 +38,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.NotAcceptableException; import javax.ws.rs.NotAcceptableException;
import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@ -343,6 +344,13 @@ public class TokenService {
return processLogin(clientId, scopeParam, state, redirect, formData); return processLogin(clientId, scopeParam, state, redirect, formData);
} }
@Path("access/codes")
@OPTIONS
@Produces("application/json")
public Response accessCodeToTokenPreflight() {
return Cors.add(request, Response.ok()).auth().preflight().build();
}
@Path("access/codes") @Path("access/codes")
@POST @POST
@Produces("application/json") @Produces("application/json")
@ -418,7 +426,7 @@ public class TokenService {
.generateIDToken() .generateIDToken()
.generateRefreshToken().build(); .generateRefreshToken().build();
return Cors.add(request, Response.ok(res)).allowedOrigins(client).allowedMethods("POST").build(); return Cors.add(request, Response.ok(res)).auth().allowedOrigins(client).allowedMethods("POST").build();
} }
protected ClientModel authorizeClient(String authorizationHeader) { protected ClientModel authorizeClient(String authorizationHeader) {