diff --git a/COPYING b/COPYING index 852b31795..8ef8ed306 100644 --- a/COPYING +++ b/COPYING @@ -141,6 +141,11 @@ Files: lemonldap-ng-manager/site/static/bwr/es5-shim/* Copyright: 2009-2015, Kristopher Michael Kowal and contributors License: Expat +Files: lemonldap-ng-portal/site/static/bwr/crypto-js/* +Copyright: 2009-2013 Jeff Mott + 2013-2016 Evan Vosberg +License: Expat + Files: debian/* Copyright: 2005-2016, Xavier Guimard License: GPL-2+ diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 2e8ce07c4..45b453903 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -115,7 +115,6 @@ lib/Lemonldap/NG/Portal/UserDBGoogle.pm lib/Lemonldap/NG/Portal/UserDBMulti.pm lib/Lemonldap/NG/Portal/UserDBOpenID.pm lib/Lemonldap/NG/Portal/UserDBOpenIDConnect.pm -lib/Lemonldap/NG/Portal/UserDBProxy.pm lib/Lemonldap/NG/Portal/UserDBSAML.pm lib/Lemonldap/NG/Portal/UserDBWebID.pm Makefile.PL @@ -144,6 +143,10 @@ site/htdocs/static/bwr/bootstrap/dist/fonts/glyphicons-halflings-regular.woff site/htdocs/static/bwr/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 site/htdocs/static/bwr/bootstrap/dist/js/bootstrap.js site/htdocs/static/bwr/bootstrap/dist/js/bootstrap.min.js +site/htdocs/static/bwr/crypto-js/enc-base64.js +site/htdocs/static/bwr/crypto-js/enc-base64.min.js +site/htdocs/static/bwr/crypto-js/sha256.js +site/htdocs/static/bwr/crypto-js/sha256.min.js site/htdocs/static/bwr/jquery-ui/jquery-ui.js site/htdocs/static/bwr/jquery-ui/jquery-ui.min.js site/htdocs/static/bwr/jquery.cookie/jquery.cookie.js @@ -271,6 +274,7 @@ site/templates/common/mail_password.tpl site/templates/common/mail_register_confirm.tpl site/templates/common/mail_register_done.tpl site/templates/common/notification.xsl +site/templates/common/oidc_checksession.tpl site/templates/common/redirect.tpl site/templates/common/saml2-metadata.tpl site/templates/common/script.tpl diff --git a/lemonldap-ng-portal/bower.json b/lemonldap-ng-portal/bower.json index 8b12643c4..d5141374e 100644 --- a/lemonldap-ng-portal/bower.json +++ b/lemonldap-ng-portal/bower.json @@ -7,6 +7,7 @@ "private": true, "dependencies": { "bootstrap": "x", + "crypto-js": "x", "jquery": "2.x", "jquery-ui": "x", "jquery.cookie": "x" diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm index 4c7071fad..7ba3cb75f 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm @@ -8,6 +8,7 @@ package Lemonldap::NG::Portal::IssuerDBOpenIDConnect; use strict; use Lemonldap::NG::Portal::Simple; use String::Random qw(random_string); +use HTML::Template; use base qw(Lemonldap::NG::Portal::_OpenIDConnect); our $VERSION = '2.0.0'; @@ -1395,23 +1396,17 @@ sub issuerForAuthUser { -type => 'text/html', -access_control_allow_origin => '*' ); - print $self->start_html( - -title => 'Check Session', - -script => [ - { - -type => 'text/javascript', - -src => -'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha256.js' - }, - { - -type => 'text/javascript', - -src => -'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js' - }, - { -code => $self->getSessionManagementOPIFrameJS } - ] - ); - print $self->end_html(); + + my $checksession_tpl = + $self->getApacheHtdocsPath + . "/site/templates/common/oidc_checksession.tpl"; + + my $static_prefix = ""; #TODO + + my $template = HTML::Template->new( filename => $checksession_tpl ); + $template->param( "JS_CODE" => $self->getSessionManagementOPIFrameJS ); + $template->param( "STATIC_PREFIX" => $static_prefix ); + print $template->output; $self->quit(); } diff --git a/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.js b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.js new file mode 100644 index 000000000..e16a3cbbd --- /dev/null +++ b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.js @@ -0,0 +1,124 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex != -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); + var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= (bitsCombined) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + + return WordArray.create(words, nBytes); + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + }()); + + + return CryptoJS.enc.Base64; + +})); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.min.js b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.min.js new file mode 100644 index 000000000..6d7cbed18 --- /dev/null +++ b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/enc-base64.min.js @@ -0,0 +1 @@ +(function(a,b){if(typeof exports==="object"){module.exports=exports=b(require("./core"))}else{if(typeof define==="function"&&define.amd){define(["./core"],b)}else{b(a.CryptoJS)}}}(this,function(a){(function(){var f=a;var b=f.lib;var c=b.WordArray;var e=f.enc;var d=e.Base64={stringify:function(m){var o=m.words;var q=m.sigBytes;var h=this._map;m.clamp();var n=[];for(var l=0;l>>2]>>>(24-(l%4)*8))&255;var r=(o[(l+1)>>>2]>>>(24-((l+1)%4)*8))&255;var p=(o[(l+2)>>>2]>>>(24-((l+2)%4)*8))&255;var s=(t<<16)|(r<<8)|p;for(var k=0;(k<4)&&(l+k*0.75>>(6*(3-k)))&63))}}var g=h.charAt(64);if(g){while(n.length%4){n.push(g)}}return n.join("")},parse:function(q){var n=q.length;var h=this._map;var g=h.charAt(64);if(g){var r=q.indexOf(g);if(r!=-1){n=r}}var o=[];var m=0;for(var l=0;l>>(6-(l%4)*2);var p=k|j;o[m>>>2]|=(p)<<(24-(m%4)*8);m++}}return c.create(o,m)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}());return a.enc.Base64})); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.js b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.js new file mode 100644 index 000000000..de2d7fca1 --- /dev/null +++ b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.js @@ -0,0 +1,199 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + return CryptoJS.SHA256; + +})); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.min.js b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.min.js new file mode 100644 index 000000000..e17c21976 --- /dev/null +++ b/lemonldap-ng-portal/site/htdocs/static/bwr/crypto-js/sha256.min.js @@ -0,0 +1 @@ +(function(a,b){if(typeof exports==="object"){module.exports=exports=b(require("./core"))}else{if(typeof define==="function"&&define.amd){define(["./core"],b)}else{b(a.CryptoJS)}}}(this,function(a){(function(d){var b=a;var c=b.lib;var h=c.WordArray;var f=c.Hasher;var i=b.algo;var k=[];var j=[];(function(){function o(s){var r=d.sqrt(s);for(var q=2;q<=r;q++){if(!(s%q)){return false}}return true}function m(q){return((q-(q|0))*4294967296)|0}var p=2;var l=0;while(l<64){if(o(p)){if(l<8){k[l]=m(d.pow(p,1/2))}j[l]=m(d.pow(p,1/3));l++}p++}}());var e=[];var g=i.SHA256=f.extend({_doReset:function(){this._hash=new h.init(k.slice(0))},_doProcessBlock:function(o,n){var r=this._hash.words;var E=r[0];var D=r[1];var C=r[2];var B=r[3];var A=r[4];var z=r[5];var y=r[6];var x=r[7];for(var w=0;w<64;w++){if(w<16){e[w]=o[n+w]|0}else{var m=e[w-15];var G=((m<<25)|(m>>>7))^((m<<14)|(m>>>18))^(m>>>3);var s=e[w-2];var F=((s<<15)|(s>>>17))^((s<<13)|(s>>>19))^(s>>>10);e[w]=G+e[w-7]+F+e[w-16]}var t=(A&z)^(~A&y);var l=(E&D)^(E&C)^(D&C);var v=((E<<30)|(E>>>2))^((E<<19)|(E>>>13))^((E<<10)|(E>>>22));var u=((A<<26)|(A>>>6))^((A<<21)|(A>>>11))^((A<<7)|(A>>>25));var q=x+u+t+j[w]+e[w];var p=v+l;x=y;y=z;z=A;A=(B+q)|0;B=C;C=D;D=E;E=(q+p)|0}r[0]=(r[0]+E)|0;r[1]=(r[1]+D)|0;r[2]=(r[2]+C)|0;r[3]=(r[3]+B)|0;r[4]=(r[4]+A)|0;r[5]=(r[5]+z)|0;r[6]=(r[6]+y)|0;r[7]=(r[7]+x)|0},_doFinalize:function(){var n=this._data;var o=n.words;var l=this._nDataBytes*8;var m=n.sigBytes*8;o[m>>>5]|=128<<(24-m%32);o[(((m+64)>>>9)<<4)+14]=d.floor(l/4294967296);o[(((m+64)>>>9)<<4)+15]=l;n.sigBytes=o.length*4;this._process();return this._hash},clone:function(){var l=f.clone.call(this);l._hash=this._hash.clone();return l}});b.SHA256=f._createHelper(g);b.HmacSHA256=f._createHmacHelper(g)}(Math));return a.SHA256})); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/oidc_checksession.tpl b/lemonldap-ng-portal/site/templates/common/oidc_checksession.tpl new file mode 100644 index 000000000..c7c5a651e --- /dev/null +++ b/lemonldap-ng-portal/site/templates/common/oidc_checksession.tpl @@ -0,0 +1,20 @@ + + + Check Session + + + + + + + + +