Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alexander.pace/server
  • geoffrey.mo/gracedb-server
  • deep.chatterjee/gracedb-server
  • cody.messick/server
  • sushant.sharma-chaudhary/server
  • michael-coughlin/server
  • daniel.wysocki/gracedb-server
  • roberto.depietri/gracedb
  • philippe.grassia/gracedb
  • tri.nguyen/gracedb
  • jonah-kanner/gracedb
  • brandon.piotrzkowski/gracedb
  • joseph-areeda/gracedb
  • duncanmmacleod/gracedb
  • thomas.downes/gracedb
  • tanner.prestegard/gracedb
  • leo-singer/gracedb
  • computing/gracedb/server
18 results
Show changes
Showing
with 3290 additions and 0 deletions
#
# Note: Changes made here should be reflected in the windows .bat file at src/build.bat
#
INSTALL=/usr/bin/install
JAVA=java
TAR=tar
ZIP=zip
TARGET=shibboleth-embedded-ds-1.2.0
prefix=
sysconfdir=${prefix}/etc
all:
install: index.html
${INSTALL} -d $(DESTDIR)${sysconfdir}/shibboleth-ds
${INSTALL} -m 644 *.txt *.html *.css *.gif *.js *.conf $(DESTDIR)${sysconfdir}/shibboleth-ds
clean:
rm -rf ${TARGET}
kit: clean
mkdir ${TARGET}
mkdir ${TARGET}/nonminimised
cat src/javascript/idpselect_languages.js src/javascript/typeahead.js src/javascript/idpselect.js | ${JAVA} -jar build/yuicompressor-2.4.8.jar -o ${TARGET}/idpselect.js --type js
cp Makefile shibboleth-embedded-ds.spec LICENSE.txt doc/*.txt src/resources/index.html src/resources/idpselect.css src/resources/blank.gif src/javascript/idpselect_config.js src/apache/*.conf ${TARGET}
cp src/javascript/*.js ${TARGET}/nonminimised
dist: kit
${TAR} czf ${TARGET}.tar.gz ${TARGET}/*
${ZIP} ${TARGET}.zip ${TARGET}/*
rm -rf ${TARGET}
Welcome to the Shibboleth Embedded Discovery Service.
Shibboleth is a federated web authentication and attribute exchange
system based on SAML. The Embedded Discovery Service allows anyone
running a suitable SP to quickly and easily deploy IdP discovery.
For full instructions on installation and deployment please read:
https://wiki.shibboleth.net/confluence/display/EDS10
INSTALLED FILES.
================
The following files will be installed, please consult the documentation
for more details.
index.html - An example file showing how to embed the EDS into a
standard webpage.
idpselect.js - The minified sources for the EDS. DO NOT EDIT THIS FILE
since it will be updated by future releases.
idpselect_config.js - Configuration. Edit this file according to the
documentation (cited above).
idpselect.css - CSS for the EDS. You may wish to edit this file.
README.TXT - This file
RELEASE-NOTES.TXT - The list of bugs fixed in this and previous releases.
FURTHER DETAILS.
================
Shibboleth is licensed under the Apache 2.0 license which is provided in the
LICENSE.txt file.
Shibboleth Project Site:
http://shibboleth.internet2.edu/
Shibboleth Documentation Site:
https://wiki.shibboleth.net/confluence/display/SHIB2/Home
Source and binary distributions
http://www.shibboleth.net/downloads/
Bug Tracker:
https://issues.shibboleth.net/
Other sources:
This tools embeds the JSON parsing tool from https://github.com/douglascrockford/JSON-js
The build process uses the yui compressor (http://developer.yahoo.com/yui/compressor/)
See https://issues.shibboleth.net/jira/projects/EDS
docker/shibboleth-ds/blank.gif

43 B

/* Top level is idpSelectIdPSelector */
#idpSelectIdPSelector
{
width:fit-content;
text-align: center;
background-color: #FFFFFF;
border: 2px #A40000 solid;
padding: 10px;
margin-top:25px;
margin-bottom:25px;
}
/* Next down are the idpSelectPreferredIdPTile, idpSelectIdPEntryTile & idpSelectIdPListTile */
/**
* The preferred IdP tile (if present) has a specified height, so
* we can fit the preselected * IdPs in there
*/
#idpSelectPreferredIdPTile
{
height: 138px /* Force the height so that the selector box
* goes below when there is only one preslect
*/
}
#idpSelectPreferredIdPTileNoImg
{
height:60px;
}
/***
* The preselect buttons
*/
div.IdPSelectPreferredIdPButton
{
margin: 3px;
width: 120px; /* Make absolute because 3 of these must fit inside
div.IdPSelect{width} with not much each side. */
float: left;
}
/*
* Make the entire box look like a hyperlink
*/
div.IdPSelectPreferredIdPButton a
{
float: left;
width: 99%; /* Need a specified width otherwise we'll fit
the contents which we don't want because
they have auto margins */
}
div.IdPSelectTextDiv{
height: 3.5ex; /* Add some height to separate the text from the boxes */
font-size: 15px;
clear: left;
}
div.IdPSelectPreferredIdPImg
{
/* max-width: 95%; */
height: 69px; /* We need the absolute height to force all buttons to the same size */
margin: 2px;
}
img.IdPSelectIdPImg {
width:auto;
}
div.IdPSelectautoDispatchTile {
display: block;
}
div.IdPSelectautoDispatchArea {
margin-top: 30px ;
}
div.IdPSelectPreferredIdPButton img
{
display: block; /* Block display to allow auto centring */
max-width: 114px; /* Specify max to allow scaling, percent does work */
max-height: 64px; /* Specify max to allow scaling, percent doesn't work */
margin-top: 3px ;
margin-bottom: 3px ;
border: solid 0px #000000; /* Strip any embellishments the brower may give us */
margin-left: auto; /* Auto centring */
margin-right: auto; /* Auto centring */
}
div.IdPSelectPreferredIdPButton div.IdPSelectTextDiv
{
text-align: center;
font-size: 12px;
font-weight: normal;
max-width: 95%;
height: 30px; /* Specify max height to allow two lines. The
* Javascript controlls the max length of the
* strings
*/
}
/*
* Force the size of the selectors and the buttons
*/
#idpSelectInput, #idpSelectSelector
{
width: 80%;
}
/*
* For some reason a <select> width includes the border and an
* <input> doesn't hence we have to force a margin onto the <select>
*/
#idpSelectSelector
{
margin-left: 2px;
margin-right: 2px;
}
#idpSelectSelectButton, #idpSelectListButton
{
margin-left: 5px;
width: 16%;
}
#idpSelectSelectButton
{
padding-left: 2px;
padding-right: 2px;
}
/*
* change underlining of HREFS
*/
#idpSelectIdPSelector a:link
{
text-decoration: none;
}
#idpSelectIdPSelector a:visited
{
text-decoration: none;
}
#idpSelectIdPSelector a:hover
{
text-decoration: underline;
}
/*
* Arrange to have the dropdown/list aref on the left and the
* help button on the right
*/
a.IdPSelectDropDownToggle
{
display: inline-block;
width: 80%;
}
a.IdPSelectHelpButton
{
display: inline-block;
text-align: right;
width: 20%;
}
/**
* Drop down (incremental search) stuff - see the associated javascript for reference
*/
ul.IdPSelectDropDown {
-moz-box-sizing: border-box;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: small;
box-sizing: border-box;
list-style: none;
padding-left: 0px;
border: 1px solid black;
z-index: 6;
position: absolute;
}
ul.IdPSelectDropDown li {
background-color: white;
cursor: default;
padding: 0px 3px;
}
ul.IdPSelectDropDown li.IdPSelectCurrent {
background-color: #3366cc;
color: white;
}
/* Legacy */
div.IdPSelectDropDown {
-moz-box-sizing: border-box;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: small;
box-sizing: border-box;
border: 1px solid black;
z-index: 6;
position: absolute;
}
div.IdPSelectDropDown div {
background-color: white;
cursor: default;
padding: 0px 3px;
}
div.IdPSelectDropDown div.IdPSelectCurrent {
background-color: #3366cc;
color: white;
}
/* END */
function IdPSelectLanguages(){this.langBundles={en:{"fatal.divMissing":'<div> specified as "insertAtDiv" could not be located in the HTML',"fatal.noXMLHttpRequest":"Browser does not support XMLHttpRequest, unable to load IdP selection data","fatal.wrongProtocol":'Policy supplied to DS was not "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',"fatal.wrongEntityId":"entityId supplied by SP did not match configuration","fatal.noData":"Metadata download returned no data","fatal.loadFailed":"Failed to download metadata from ","fatal.noparms":"No parameters to discovery session and no defaultReturn parameter configured","fatal.noReturnURL":"No URL return parameter provided","fatal.badProtocol":"Return request must start with https:// or http://","idpPreferred.label":"Use a suggested selection:","idpEntry.label":"Or enter your organization's name","idpEntry.NoPreferred.label":"Enter your organization's name","idpList.label":"Or select your organization from the list below","idpList.NoPreferred.label":"Select your organization from the list below","idpList.defaultOptionLabel":"Please select your organization...","idpList.showList":"Allow me to pick from a list","idpList.showSearch":"Allow me to specify the site","submitButton.label":"Continue",helpText:"Help",defaultLogoAlt:"DefaultLogo","autoFollow.message":"Always follows this selection","autoFollow.never":"Never","autoFollow.time0":"One day","autoFollow.time1":"3 months","autoFollow.time2":"9 months"},de:{"fatal.divMissing":"Das notwendige Div Element fehlt","fatal.noXMLHttpRequest":"Ihr Webbrowser unterst\u00fctzt keine XMLHttpRequests, IdP-Auswahl kann nicht geladen werden","fatal.wrongProtocol":'DS bekam eine andere Policy als "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',"fatal.wrongEntityId":"Die entityId ist nicht korrekt","fatal.loadFailed":"Metadaten konnten nicht heruntergeladen werden: ","fatal.noparms":"Parameter f\u00fcr das Discovery Service oder 'defaultReturn' fehlen","fatal.noReturnURL":"URL return Parmeter fehlt","fatal.badProtocol":"return Request muss mit https:// oder http:// beginnen","idpPreferred.label":"Vorherige Auswahl:","idpEntry.label":"Oder geben Sie den Namen (oder Teile davon) an:","idpEntry.NoPreferred.label":"Namen (oder Teile davon) der Institution angeben:","idpList.label":"Oder w\u00e4hlen Sie Ihre Institution aus einer Liste:","idpList.NoPreferred.label":"Institution aus folgender Liste w\u00e4hlen:","idpList.defaultOptionLabel":"W\u00e4hlen Sie Ihre Institution aus...","idpList.showList":"Institution aus einer Liste w\u00e4hlen","idpList.showSearch":"Institution selbst angeben","submitButton.label":"OK",helpText:"Hilfe",defaultLogoAlt:"Standard logo"},ja:{"fatal.divMissing":'"insertAtDiv" の ID を持つ <div> が HTML 中に存在しません',"fatal.noXMLHttpRequest":"ブラウザが XMLHttpRequest をサポートしていないので IdP 情報を取得できません","fatal.wrongProtocol":'DSへ渡された Policy パラメータが "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single" ではありません',"fatal.wrongEntityId":"SP から渡された entityId が設定値と異なります","fatal.noData":"メタデータが空です","fatal.loadFailed":"次の URL からメタデータをダウンロードできませんでした: ","fatal.noparms":"DSにパラメータが渡されておらず defaultReturn も設定されていません","fatal.noReturnURL":"戻り URL が指定されていません","fatal.badProtocol":"戻り URL は https:// か http:// で始まらなければなりません","idpPreferred.label":"選択候補の IdP:","idpEntry.label":"もしくはあなたの所属機関名を入力してください","idpEntry.NoPreferred.label":"あなたの所属機関名を入力してください","idpList.label":"もしくはあなたの所属機関を選択してください","idpList.NoPreferred.label":"あなたの所属機関を一覧から選択してください","idpList.defaultOptionLabel":"所属機関を選択してください...","idpList.showList":"一覧から選択する","idpList.showSearch":"機関名を入力する","submitButton.label":"選択","autoFollow.message":"次の期間選択した機関に自動的に遷移する:","autoFollow.never":"自動遷移しない","autoFollow.time0":"1日","autoFollow.time1":"3か月","autoFollow.time2":"9か月",helpText:"Help",defaultLogoAlt:"DefaultLogo"},"pt-br":{"fatal.divMissing":'A tag <div> com "insertAtDiv" não foi encontrada no arquivo HTML',"fatal.noXMLHttpRequest":'Seu navegador não suporta "XMLHttpRequest", impossível de carregador os dados do IdP selecionado',"fatal.wrongProtocol":'A política "Policy" fornecida para o DS não foi "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',"fatal.wrongEntityId":"entityId oferecido pelo SP não confere com o da configuração","fatal.noData":"O arquivo de metadados não retornou nada;","fatal.loadFailed":"Falhou ao realizar download do metadado de ","fatal.noparms":'Sem parâmetros para sessão de descoberta e sem parâmetro "defaultReturn" configurado',"fatal.noReturnURL":"Não foi definida um endereço (URL) de retorno no parâmetro","fatal.badProtocol":"Retorno do endereço requisitado deve começar com https:// ou http://","idpPreferred.label":"Use estas Instituições sugeridas: ","idpEntry.label":"Ou informe o nome da sua Instituição","idpEntry.NoPreferred.label":"Informe o nome da sua Instituição","idpList.label":"Ou selecione sua Instituição através da lista abaixo","idpList.NoPreferred.label":"Selecione sua Instituição através da lista abaixo","idpList.defaultOptionLabel":"Por favor, selecione sua Instituição: ","idpList.showList":"Permitir que eu escolha um IdP através de uma lista","idpList.showSearch":"Permitir que eu especifique o IdP","submitButton.label":"Continuar ",helpText:"Ajuda",defaultLogoAlt:"Logo padrão"}}}function TypeAheadControl(l,f,j,g,i,b,h,e,a,c,d,k){this.elementList=l;this.textBox=f;this.origin=j;this.submit=g;this.results=0;this.alwaysShow=c;this.maxResults=d;this.ie6hack=a;this.maxchars=i;this.getName=b;this.getEntityId=h;this.geticon=e;this.getKeywords=k}TypeAheadControl.prototype.draw=function(b){var a=this;this.dropDown=document.createElement("ul");this.dropDown.className="IdPSelectDropDown";this.dropDown.style.visibility="hidden";this.dropDown.style.width=this.textBox.offsetWidth;this.dropDown.current=-1;this.textBox.setAttribute("role","listbox");document.body.appendChild(this.dropDown);this.textBox.setAttribute("role","combobox");this.textBox.setAttribute("aria-controls","IdPSelectDropDown");this.textBox.setAttribute("aria-owns","IdPSelectDropDown");this.dropDown.onmouseover=function(c){if(!c){c=window.event}var d;if(c.target){d=c.target}if(typeof d=="undefined"){d=c.srcElement}a.select(d)};this.dropDown.onmousedown=function(c){if(-1!=a.dropDown.current){a.textBox.value=a.results[a.dropDown.current][0]}};this.textBox.onkeyup=function(c){if(!c){c=window.event}a.handleKeyUp(c)};this.textBox.onkeydown=function(c){if(!c){c=window.event}a.handleKeyDown(c)};this.textBox.onblur=function(){a.hideDrop()};this.textBox.onfocus=function(){a.handleChange()};if(null==b||b){this.textBox.focus()}};TypeAheadControl.prototype.getPossible=function(b){var h=[];var j=0;var f=0;var e=0;var g;var i;b=b.toLowerCase();while(f<=this.maxResults&&j<this.elementList.length){var a=false;var c=this.getName(this.elementList[j]);if(c.toLowerCase().indexOf(b)!=-1){a=true}if(!a&&this.getEntityId(this.elementList[j]).toLowerCase().indexOf(b)!=-1){a=true}if(!a){var d=this.getKeywords(this.elementList[j]);if(null!=d&&d.toLowerCase().indexOf(b)!=-1){a=true}}if(a){h[f]=[c,this.getEntityId(this.elementList[j]),this.geticon(this.elementList[j])];f++}j++}this.dropDown.current=-1;return h};TypeAheadControl.prototype.handleKeyUp=function(b){var a=b.keyCode;if(27==a){this.textBox.value="";this.handleChange()}else{if(8==a||32==a||(a>=46&&a<112)||a>123){this.handleChange()}}};TypeAheadControl.prototype.handleKeyDown=function(b){var a=b.keyCode;if(38==a){this.upSelect()}else{if(40==a){this.downSelect()}}};TypeAheadControl.prototype.hideDrop=function(){var a=0;if(null!==this.ie6hack){while(a<this.ie6hack.length){this.ie6hack[a].style.visibility="visible";a++}}this.dropDown.style.visibility="hidden";this.textBox.setAttribute("aria-expanded","false");if(-1==this.dropDown.current){this.doUnselected()}};TypeAheadControl.prototype.showDrop=function(){var a=0;if(null!==this.ie6hack){while(a<this.ie6hack.length){this.ie6hack[a].style.visibility="hidden";a++}}this.dropDown.style.visibility="visible";this.dropDown.style.width=this.textBox.offsetWidth+"px";this.textBox.setAttribute("aria-expanded","true")};TypeAheadControl.prototype.doSelected=function(){this.submit.disabled=false};TypeAheadControl.prototype.doUnselected=function(){this.submit.disabled=true;this.textBox.setAttribute("aria-activedescendant","")};TypeAheadControl.prototype.handleChange=function(){var b=this.textBox.value;var a=this.getPossible(b);if(0===b.length||0===a.length||(!this.alwaysShow&&this.maxResults<a.length)){this.hideDrop();this.doUnselected();this.results=[];this.dropDown.current=-1}else{this.results=a;this.populateDropDown(a);if(1==a.length){this.select(this.dropDown.childNodes[0]);this.doSelected()}else{this.doUnselected()}}};TypeAheadControl.prototype.populateDropDown=function(d){this.dropDown.innerHTML="";var c=0;var a;var b;var f;while(c<d.length){a=document.createElement("li");a.id="IdPSelectOption"+c;f=d[c][0];if(null!==d[c][2]){b=document.createElement("img");b.src=d[c][2];b.width=16;b.height=16;b.alt="";a.appendChild(b);if(f.length>this.maxchars-2){f=f.substring(0,this.maxchars-2)}f=" "+f}else{if(f.length>this.maxchars){f=f.substring(0,this.maxchars)}}a.appendChild(document.createTextNode(f));a.setAttribute("role","option");this.dropDown.appendChild(a);c++}var e=this.getXY();this.dropDown.style.left=e[0]+"px";this.dropDown.style.top=e[1]+"px";this.showDrop()};TypeAheadControl.prototype.getXY=function(){var a=this.textBox;var c=0;var b=a.offsetHeight;while(a.tagName!="BODY"){c+=a.offsetLeft;b+=a.offsetTop;a=a.offsetParent}c+=a.offsetLeft;b+=a.offsetTop;return[c,b]};TypeAheadControl.prototype.select=function(b){var a=0;var c;this.dropDown.current=-1;this.doUnselected();while(a<this.dropDown.childNodes.length){c=this.dropDown.childNodes[a];if(c==b){c.className="IdPSelectCurrent";c.setAttribute("aria-selected","true");this.textBox.setAttribute("aria-activedescendant","IdPSelectOption"+a);this.doSelected();this.dropDown.current=a;this.origin.value=this.results[a][1];this.origin.textValue=this.results[a][0]}else{c.setAttribute("aria-selected","false");c.className=""}a++}this.textBox.focus()};TypeAheadControl.prototype.downSelect=function(){if(this.results.length>0){if(-1==this.dropDown.current){this.dropDown.current=0;this.dropDown.childNodes[0].className="IdPSelectCurrent";this.dropDown.childNodes[0].setAttribute("aria-selected","true");this.textBox.setAttribute("aria-activedescendant","IdPSelectOption"+0);this.doSelected();this.origin.value=this.results[0][1];this.origin.textValue=this.results[0][0]}else{if(this.dropDown.current<(this.results.length-1)){this.dropDown.childNodes[this.dropDown.current].className="";this.dropDown.current++;this.dropDown.childNodes[this.dropDown.current].className="IdPSelectCurrent";this.dropDown.childNodes[this.dropDown.current].setAttribute("aria-selected","true");this.textBox.setAttribute("aria-activedescendant","IdPSelectOption"+this.dropDown.current);this.doSelected();this.origin.value=this.results[this.dropDown.current][1];this.origin.textValue=this.results[this.dropDown.current][0]}}}};TypeAheadControl.prototype.upSelect=function(){if((this.results.length>0)&&(this.dropDown.current>0)){this.dropDown.childNodes[this.dropDown.current].className="";this.dropDown.current--;this.dropDown.childNodes[this.dropDown.current].className="IdPSelectCurrent";this.dropDown.childNodes[this.dropDown.current].setAttribute("aria-selected","true");this.textBox.setAttribute("aria-activedescendant","IdPSelectOption"+this.dropDown.current);this.doSelected();this.origin.value=this.results[this.dropDown.current][1];this.origin.textValue=this.results[this.dropDown.current][0]}};function IdPSelectUI(){var q;var V="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var aH;var R;var az;var al;var Z;var d;var E;var m;var x;var j;var au;var f;var s;var aa;var af;var C;var ae;var Q;var g;var J;var ar;var M;var S;var aj;var av;var ao;var c;var ad;var F;var P;var Y;var O;var T;var i;var ax;var U;var aJ="idpSelect";var ah="IdPSelect";var ap;var A="";var X="";var ay=[];var aE="entityID";this.draw=function(aN){if(!l(aN)){return}aH=document.getElementById(aN.insertAtDiv);if(!aH){N(z("fatal.divMissing"));return}if((null!=P)&&(null!=h(P))){var aK=b();if(aK.length!=0){var aM=aE+"="+encodeURIComponent(aK[0]);if(A.indexOf("?")==-1){aM="?"+aM}else{aM="&"+aM}p(aH,A+aM);return}}if(!e(aN.dataSource)){return}aI();t(aN.hiddenIdPs);q.sort(function(aP,aO){return aC(aP).localeCompare(aC(aO))});var aL=ab();aH.appendChild(aL);ap.draw(aN.setFocusTextBox)};var l=function(aR){var aL;C=aR.preferredIdP;ae=aR.maxPreferredIdPs;Q=aR.helpURL;g=aR.ie6Hack;J=aR.samlIdPCookieTTL;aj=aR.alwaysShow;av=aR.maxResults;ao=aR.ignoreKeywords;if(aR.showListFirst){c=aR.showListFirst}else{c=false}if(aR.noWriteCookie){ad=aR.noWriteCookie}else{ad=false}if(aR.ignoreURLParams){F=aR.ignoreURLParams}else{F=false}E=aR.defaultLogo;m=aR.defaultLogoWidth;x=aR.defaultLogoHeight;j=aR.minWidth;au=aR.minHeight;f=aR.maxWidth;s=aR.maxHeight;aa=aR.bestRatio;if(null==aR.doNotCollapse){af=true}else{af=aR.doNotCollapse}M=aR.maxIdPCharsButton;ar=aR.maxIdPCharsDropDown;S=aR.maxIdPCharsAltTxt;P=aR.autoFollowCookie;Y=aR.autoFollowCookieTTLs;var a1;if(typeof navigator=="undefined"){a1=aR.defaultLanguage}else{a1=navigator.language||navigator.userLanguage||aR.defaultLanguage}a1=a1.toLowerCase();if(a1.indexOf("-")>0){az=a1.substring(0,a1.indexOf("-"))}var aV=new IdPSelectLanguages();al=aR.defaultLanguage;if(typeof aR.langBundles!="undefined"&&typeof aR.langBundles[a1]!="undefined"){Z=aR.langBundles[a1]}else{if(typeof aV.langBundles[a1]!="undefined"){Z=aV.langBundles[a1]}else{if(typeof az!="undefined"){if(typeof aR.langBundles!="undefined"&&typeof aR.langBundles[az]!="undefined"){Z=aR.langBundles[az]}else{if(typeof aV.langBundles[az]!="undefined"){Z=aV.langBundles[az]}}}}}if(typeof aR.langBundles!="undefined"&&typeof aR.langBundles[aR.defaultLanguage]!="undefined"){d=aR.langBundles[aR.defaultLanguage]}else{d=aV.langBundles[aR.defaultLanguage]}if(!d){N("No languages work");return false}if(!Z){r("No language support for "+a1);Z=d}if(aR.testGUI){return true}var aW="urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single";var aZ;var a0=false;var aP;var aS;var aO=window;while(null!==aO.parent&&aO!==aO.parent){aO=aO.parent}var aU=aO.location;var aQ=aU.search;if(F||null==aQ||0==aQ.length||aQ.charAt(0)!="?"){if((null==aR.defaultReturn)&&!F){N(z("fatal.noparms"));return false}aL=aR.myEntityID;A=aR.defaultReturn;if(null!=aR.defaultReturnIDParam){aE=aR.defaultReturnIDParam}}else{aQ=aQ.substring(1);aP=aQ.split("&");if(aP.length===0){N(z("fatal.noparms"));return false}for(aZ=0;aZ<aP.length;aZ++){aS=aP[aZ].split("=");if(aS.length!=2){continue}if(aS[0]=="entityID"){aL=decodeURIComponent(aS[1])}else{if(aS[0]=="return"){A=decodeURIComponent(aS[1])}else{if(aS[0]=="returnIDParam"){aE=decodeURIComponent(aS[1])}else{if(aS[0]=="policy"){aW=decodeURIComponent(aS[1])}else{if(aS[0]=="isPassive"){a0=(aS[1].toUpperCase()=="TRUE")}}}}}}}var aK;if(null==aR.allowableProtocols){aK=["urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"]}else{aK=aR.allowableProtocols}var aY=false;for(var aZ=0;aZ<aK.length;aZ++){var aX=aK[aZ];if(aW==aX){aY=true;break}}if(!aY){N(z("fatal.wrongProtocol"));return false}if(aR.myEntityID!==null&&aR.myEntityID!=aL){N(z("fatal.wrongEntityId")+'"'+aL+'" != "'+aR.myEntityID+'"');return false}if(null===A||A.length===0){N(z("fatal.noReturnURL"));return false}if(!am(A)){N(z("fatal.badProtocol"));return false}if(a0){var aN=b();var aT=document.getElementById(parmsSupplied.insertAtDiv);if(aN.length==0){p(aT,A);return false}else{var aM=aE+"="+encodeURIComponent(aN[0]);if(A.indexOf("?")==-1){aM="?"+aM}else{aM="&"+aM}p(aT,A+aM);return false}}aZ=A.indexOf("?");if(aZ<0){X=A;return true}X=A.substring(0,aZ);aQ=A.substring(aZ+1);aP=aQ.split("&");for(aZ=0;aZ<aP.length;aZ++){aS=aP[aZ].split("=");if(aS.length!=2){continue}aS[1]=decodeURIComponent(aS[1]);ay.push(aS)}return true};var aI=function(){var aM=[];var aL;for(aL=0;aL<q.length;){var aK=y(q[aL]);if(null==aM[aK]){aM[aK]=aK;aL=aL+1}else{q.splice(aL,1)}}};var t=function(aM){if(null==aM||0==aM.length){return}var aL;var aK;for(aL=0;aL<aM.length;aL++){for(aK=0;aK<q.length;aK++){if(y(q[aK])==aM[aL]){q.splice(aK,1);break}}}};var am=function(aL){if(null===aL){return false}var aK="://";var aM=aL.indexOf(aK);if(aM<0){return false}aL=aL.substring(0,aM);if(aL=="http"||aL=="https"){return true}return false};var aG=function(){if(null==navigator){return false}var aK=navigator.appName;if(null==aK){return false}return(aK=="Microsoft Internet Explorer")};var p=function(aL,aM){var aK=document.createElement("a");aK.href=aM;aL.appendChild(aK);aK.click()};var e=function(aN){var aM=null;try{aM=new XMLHttpRequest()}catch(aL){}if(null==aM){try{aM=new ActiveXObject("Microsoft.XMLHTTP")}catch(aL){}}if(null==aM){try{aM=new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(aL){}}if(null==aM){N(z("fatal.noXMLHttpRequest"));return false}if(aG()){aN+="?random="+(Math.random()*1000000)}aM.open("GET",aN,false);if(typeof aM.overrideMimeType=="function"){aM.overrideMimeType("application/json")}aM.send(null);if(aM.status==200){var aK=aM.responseText;if(aK===null){N(z("fatal.noData"));return false}q=JSON.parse(aK)}else{N(z("fatal.loadFailed")+aN);return false}return true};var ac=function(aK){for(var aL=0;aL<q.length;aL++){if(y(q[aL])==aK){return q[aL]}}return null};var G=function(aR,aL){var aQ=function(aU){var aS=null;var aT;if(null==aR.Logos){return null}for(aT in aR.Logos){if(aR.Logos[aT].lang==aU&&aR.Logos[aT].width!=null&&aR.Logos[aT].width>=j&&aR.Logos[aT].height!=null&&aR.Logos[aT].height>=au){if(aS===null){aS=aR.Logos[aT]}else{me=Math.abs(aa-Math.log(aR.Logos[aT].width/aR.Logos[aT].height));him=Math.abs(aa-Math.log(aS.width/aS.height));if(him>me){aS=aR.Logos[aT]}}}}return aS};var aN=null;var aM=document.createElement("img");ak(aM,"IdPImg");aN=aQ(R);if(null===aN&&typeof az!="undefined"){aN=aQ(az)}if(null===aN){aN=aQ(null)}if(null===aN){aN=aQ(al)}if(null===aN){if(!aL){return null}aM.src=E;aM.width=m;aM.height=x;aM.alt=z("defaultLogoAlt");return aM}aM.src=aN.value;var aO=aC(aR);if(aO.length>S){aO=aO.substring(0,S)+"..."}aM.alt=aO;var aK=aN.width;var aP=aN.height;if(aK>f){aP=(f/aK)*aP;aK=f}if(aP>s){aK=(s/aP)*aK;aP=s}aM.setAttribute("width",aK);aM.setAttribute("height",aP);return aM};var ab=function(){var aL=an("IdPSelector");var aK;aK=aA(aL);n(aL,aK);W(aL,aK);if(null!=P){B(aL)}return aL};var L=function(aM,aT,aL){var aK=an(undefined,"PreferredIdPButton");var aS=document.createElement("a");var aR=aE+"="+encodeURIComponent(y(aM));var aN=A;var aP=G(aM,aL);if(aN.indexOf("?")==-1){aR="?"+aR}else{aR="&"+aR}aS.href=aN+aR;aS.onclick=function(){aF(y(aM))};if(null!=aP){var aU=an(undefined,"PreferredIdPImg");aU.appendChild(aP);aS.appendChild(aU)}var aQ=an(undefined,"TextDiv");var aO=aC(aM);if(aO.length>M){aO=aO.substring(0,M)+"..."}aK.title=aO;aQ.appendChild(document.createTextNode(aO));aS.appendChild(aQ);aK.appendChild(aS);return aK};var aD=function(aK,aN){var aM=an(undefined,"TextDiv");var aL=document.createTextNode(z(aN));aM.appendChild(aL);aK.appendChild(aM)};var a=function(aK,aM){if(null===aM||0===aM.length||"-"==aM.value){return}var aL=0;while(aL<aK.options.length){if(aK.options[aL].value==aM){aK.options[aL].selected=true;break}aL++}};var aA=function(aP){var aO=K();if(0===aO.length){return false}var aK=af;for(var aM=0;aM<ae&&aM<aO.length;aM++){if(aO[aM]&&G(aO[aM],false)){aK=true}}var aN;if(aK){aN=an("PreferredIdPTile")}else{aN=an("PreferredIdPTileNoImg")}aD(aN,"idpPreferred.label");for(var aM=0;aM<ae&&aM<aO.length;aM++){if(aO[aM]){var aL=L(aO[aM],aM,aK);aN.appendChild(aL)}}aP.appendChild(aN);return true};var ag=function(){var aL=document.createElement("form");T.appendChild(aL);aL.action=X;aL.method="GET";aL.setAttribute("autocomplete","OFF");var aK=0;for(aK=0;aK<ay.length;aK++){var aM=document.createElement("input");aM.setAttribute("type","hidden");aM.name=ay[aK][0];aM.value=ay[aK][1];aL.appendChild(aM)}return aL};var n=function(aR,aL){T=an("IdPEntryTile");if(c){T.style.display="none"}var aM=document.createElement("label");aM.setAttribute("for",aJ+"Input");if(aL){aD(aM,"idpEntry.label")}else{aD(aM,"idpEntry.NoPreferred.label")}var aP=ag();aP.appendChild(aM);var aO=document.createElement("input");aP.appendChild(aO);aO.type="text";k(aO,"Input");var aQ=document.createElement("input");aQ.setAttribute("type","hidden");aP.appendChild(aQ);aQ.name=aE;aQ.value="-";var aN=u("Select");aN.disabled=true;aP.appendChild(aN);aP.onsubmit=function(){if(null===aQ.value||0===aQ.value.length||"-"==aQ.value){return false}aO.value=aQ.textValue;aF(aQ.value);return true};ap=new TypeAheadControl(q,aO,aQ,aN,ar,aC,y,ai,g,aj,av,H);var aK=document.createElement("a");aK.appendChild(document.createTextNode(z("idpList.showList")));aK.href="#";ak(aK,"DropDownToggle");aK.onclick=function(){T.style.display="none";a(ax,aQ.value);i.style.display="";U.focus();return false};T.appendChild(aK);w(T);aR.appendChild(T)};var W=function(aK,aN){i=an("IdPListTile");if(!c){i.style.display="none"}var aR=document.createElement("label");aR.setAttribute("for",aJ+"Selector");if(aN){aD(aR,"idpList.label")}else{aD(aR,"idpList.NoPreferred.label")}ax=document.createElement("select");k(ax,"Selector");ax.name=aE;i.appendChild(ax);var aS=o("-",z("idpList.defaultOptionLabel"));aS.selected=true;ax.appendChild(aS);var aM;for(var aO=0;aO<q.length;aO++){aM=q[aO];aS=o(y(aM),aC(aM));ax.appendChild(aS)}var aL=ag();aL.appendChild(aR);aL.appendChild(ax);aL.onsubmit=function(){if(ax.selectedIndex<1){return false}aF(ax.options[ax.selectedIndex].value);return true};var aP=u("List");U=aP;aL.appendChild(aP);i.appendChild(aL);var aQ=document.createElement("a");aQ.appendChild(document.createTextNode(z("idpList.showSearch")));aQ.href="#";ak(aQ,"DropDownToggle");aQ.onclick=function(){T.style.display="";i.style.display="none";return false};i.appendChild(aQ);w(i);aK.appendChild(i)};var B=function(aN){var aL="IdPSelectAutoDisp";autoDispatchTile=an(undefined,"autoDispatchArea");autoDispatchTile.appendChild(document.createTextNode(z("autoFollow.message")));var aK=document.createElement("input");aK.setAttribute("type","radio");aK.setAttribute("checked","checked");aK.setAttribute("name",aL);aK.onclick=function(){D(0)};div=an(undefined,"autoDispatchTile");div.appendChild(aK);div.appendChild(document.createTextNode(z("autoFollow.never")));autoDispatchTile.appendChild(div);var aM;for(aM=0;aM<Y.length;aM++){aK=document.createElement("input");aK.setAttribute("type","radio");aK.setAttribute("name",aL);aK.life=Y[aM];aK.onclick=function(){var aO=this.life;D(aO)};div=an(undefined,"autoDispatchTile");div.appendChild(aK);div.appendChild(document.createTextNode(z("autoFollow.time"+aM)));autoDispatchTile.appendChild(div)}aN.appendChild(autoDispatchTile)};var u=function(aL){var aK=document.createElement("input");aK.setAttribute("type","submit");aK.value=z("submitButton.label");k(aK,aL+"Button");return aK};var w=function(aL){var aK=document.createElement("a");aK.href=Q;aK.appendChild(document.createTextNode(z("helpText")));ak(aK,"HelpButton");aL.appendChild(aK)};var an=function(aM,aK){var aL=document.createElement("div");if(undefined!==aM){k(aL,aM)}if(undefined!==aK){ak(aL,aK)}return aL};var o=function(aL,aM){var aK=document.createElement("option");aK.value=aL;if(aM.length>ar){aM=aM.substring(0,ar)}aK.appendChild(document.createTextNode(aM));return aK};var k=function(aL,aK){aL.id=aJ+aK};var ak=function(aL,aK){aL.setAttribute("class",ah+aK)};var aB=function(aK){return document.getElementById(aJ+aK)};var aF=function(aK){I(aK);aq(O)};var z=function(aK){var aL=Z[aK];if(!aL){aL=d[aK]}if(!aL){aL="Missing message for "+aK}return aL};var y=function(aK){return aK.entityID};var ai=function(aM){var aK;if(null==aM.Logos){return null}for(aK=0;aK<aM.Logos.length;aK++){var aL=aM.Logos[aK];if(aL.height=="16"&&aL.width=="16"){if(null==aL.lang||R==aL.lang||(typeof az!="undefined"&&az==aL.lang)||al==aL.lang){return aL.value}}}return null};var aC=function(aL){var aK=aw(aL.DisplayNames);if(null!==aK){return aK}r("No Name entry in any language for "+y(aL));return y(aL)};var H=function(aL){if(ao||null==aL.Keywords){return null}var aK=aw(aL.Keywords);return aK};var aw=function(aK){var aL;for(aL in aK){if(aK[aL].lang==R){return aK[aL].value}}if(typeof az!="undefined"){for(aL in aK){if(aK[aL].lang==az){return aK[aL].value}}}for(aL in aK){if(aK[aL].lang==null){return aK[aL].value}}for(aL in aK){if(aK[aL].lang==al){return aK[aL].value}}return null};var K=function(){var aO=[];var aN=0;var aM;var aL;if(null!=C){for(aM=0;aM<C.length&&aM<ae;aM++){aO[aM]=ac(C[aM]);aN++}}O=b();for(aM=aN,aL=0;aL<O.length&&aM<ae;aL++){var aK=ac(O[aL]);if(typeof aO.indexOf==="undefined"){aO.push(aK);aM++}else{if(aO.indexOf(aK)===-1){aO.push(aK);aM++}}}return aO};var I=function(aK){var aL=[];while(0!==O.length){var aM=O.pop();if(aM!=aK){aL.unshift(aM)}}aL.unshift(aK);O=aL;return};var D=function(aM){var aK;if(aM>0){var aL=new Date();cookieTTL=aM*24*60*60*1000;aK=new Date(aL.getTime()+cookieTTL)}else{aK=new Date(0)}document.cookie=P+"=1;path=/;expires="+aK.toUTCString()};var h=function(aM){var aO,aL;var aP;aP=document.cookie.split(";");for(aO=0;aO<aP.length;aO++){var aN=aP[aO];var aK=aN.indexOf("=");var aQ=aN.substring(0,aK);if(aM==(aQ.replace(/^\s+|\s+$/g,""))){return aN.substring(aK+1)}}return null};var b=function(){var aK=[];var aL;var aM=h("_saml_idp");if(aM!=null){aM=aM.replace(/^\s+|\s+$/g,"");aM=aM.replace("+","%20");aM=aM.split("%20");for(aL=aM.length;aL>0;aL--){if(0===aM[aL-1].length){continue}var aN=at(decodeURIComponent(aM[aL-1]));if(aN.length>0){aK.push(aN)}}}return aK};var aq=function(aP){var aM=[];var aO=aP.length;if(ad){return}if(aO>5){aO=5}for(var aN=aO;aN>0;aN--){if(aP[aN-1].length>0){aM.push(encodeURIComponent(v(aP[aN-1])))}}var aK=null;if(J){var aL=new Date();cookieTTL=J*24*60*60*1000;aK=new Date(aL.getTime()+cookieTTL)}document.cookie="_saml_idp="+aM.join("%20")+"; path = /"+((aK===null)?"":"; expires="+aK.toUTCString())};var v=function(aT){var aK="",aO,aM,aL,aS,aR,aQ,aP;for(var aN=0;aN<aT.length;){aO=aT.charCodeAt(aN++);aM=aT.charCodeAt(aN++);aL=aT.charCodeAt(aN++);aS=aO>>2;aR=((aO&3)<<4)+(aM>>4);aQ=((aM&15)<<2)+(aL>>6);aP=aL&63;if(isNaN(aM)){aQ=aP=64}else{if(isNaN(aL)){aP=64}}aK+=V.charAt(aS)+V.charAt(aR)+V.charAt(aQ)+V.charAt(aP)}return aK};var at=function(aN){var aL="",aU,aS,aQ,aT,aR,aP,aO;var aM=0;var aK=/[^A-Za-z0-9\+\/\=]/g;aN=aN.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{aT=V.indexOf(aN.charAt(aM++));aR=V.indexOf(aN.charAt(aM++));aP=V.indexOf(aN.charAt(aM++));aO=V.indexOf(aN.charAt(aM++));aU=(aT<<2)|(aR>>4);aS=((aR&15)<<4)|(aP>>2);aQ=((aP&3)<<6)|aO;aL=aL+String.fromCharCode(aU);if(aP!=64){aL=aL+String.fromCharCode(aS)}if(aO!=64){aL=aL+String.fromCharCode(aQ)}aU=aS=aQ="";aT=aR=aP=aO=""}while(aM<aN.length);return aL};var N=function(aL){alert("FATAL - DISCO UI:"+aL);var aK=document.createTextNode(aL);aH.appendChild(aK)};var r=function(){}}(new IdPSelectUI()).draw(new IdPSelectUIParms());
\ No newline at end of file
/** @class IdP Selector UI */
function IdPSelectUIParms(){
//
// Adjust the following to fit into your local configuration
//
this.alwaysShow = true; // If true, this will show results as soon as you start typing
this.dataSource = '/Shibboleth.sso/DiscoFeed'; // Where to get the data from
this.defaultLanguage = 'en'; // Language to use if the browser local doesnt have a bundle
this.defaultLogo = 'blank.gif'; // Replace with your own logo
this.defaultLogoWidth = 1;
this.defaultLogoHeight = 1 ;
this.defaultReturn = null; // If non null, then the default place to send users who are not
// Approaching via the Discovery Protocol for example
//this.defaultReturn = "https://example.org/Shibboleth.sso/DS?SAMLDS=1&target=https://example.org/secure";
this.defaultReturnIDParam = null;
this.helpURL = 'https://wiki.shibboleth.net/confluence/display/SHIB2/DiscoveryService'
//this.helpURL = 'https://wiki.shibboleth.net/confluence/display/SHIB2/DSRoadmap';
this.ie6Hack = null; // An array of structures to disable when drawing the pull down (needed to
// handle the ie6 z axis problem
this.insertAtDiv = 'idpSelect'; // The div where we will insert the data
this.maxResults = 10; // How many results to show at once or the number at which to
// start showing if alwaysShow is false
this.myEntityID = null; // If non null then this string must match the string provided in the DS parms
this.preferredIdP = ['https://login.ligo.org/idp/shibboleth', 'https://shibbi.pki.itc.u-tokyo.ac.jp/idp/shibboleth', 'https://google.cirrusidentity.com/gateway'];
this.hiddenIdPs = null; // Array of entityIds to delete
this.ignoreKeywords = false; // Do we ignore the <mdui:Keywords/> when looking for candidates
this.showListFirst = false; // Do we start with a list of IdPs or just the dropdown
this.samlIdPCookieTTL = 730; // in days
this.setFocusTextBox = true; // Set to false to supress focus
this.testGUI = false;
this.autoFollowCookie = null; // If you want auto-dispatch, set this to the cookie name to use
this.autoFollowCookieTTLs = [ 1, 60, 270 ]; // Cookie life (in days). Changing this requires changes to idp_select_languages
//
// Language support.
//
// The minified source provides "en", "de", "pt-br" and "jp".
//
// Override any of these below, or provide your own language
//
//this.langBundles = {
//'en': {
// 'fatal.divMissing': '<div> specified as "insertAtDiv" could not be located in the HTML',
// 'fatal.noXMLHttpRequest': 'Browser does not support XMLHttpRequest, unable to load IdP selection data',
// 'fatal.wrongProtocol' : 'Policy supplied to DS was not "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',
// 'fatal.wrongEntityId' : 'entityId supplied by SP did not match configuration',
// 'fatal.noData' : 'Metadata download returned no data',
// 'fatal.loadFailed': 'Failed to download metadata from ',
// 'fatal.noparms' : 'No parameters to discovery session and no defaultReturn parameter configured',
// 'fatal.noReturnURL' : "No URL return parameter provided",
// 'fatal.badProtocol' : "Return request must start with https:// or http://",
// 'idpPreferred.label': 'Use a suggested selection:',
// 'idpEntry.label': 'Or enter your organization\'s name',
// 'idpEntry.NoPreferred.label': 'Enter your organization\'s name',
// 'idpList.label': 'Or select your organization from the list below',
// 'idpList.NoPreferred.label': 'Select your organization from the list below',
// 'idpList.defaultOptionLabel': 'Please select your organization...',
// 'idpList.showList' : 'Allow me to pick from a list',
// 'idpList.showSearch' : 'Allow me to specify the site',
// 'submitButton.label': 'Continue',
// 'helpText': 'Help',
// 'defaultLogoAlt' : 'DefaultLogo'
//}
//};
//
// The following should not be changed without changes to the css. Consider them as mandatory defaults
//
this.maxPreferredIdPs = 4;
this.maxIdPCharsButton = 33;
this.maxIdPCharsDropDown = 58;
this.maxIdPCharsAltTxt = 60;
this.minWidth = 20;
this.minHeight = 20;
this.maxWidth = 115;
this.maxHeight = 69;
this.bestRatio = Math.log(80 / 60);
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<title>IDP select test bed</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-5" />
<link rel="stylesheet" type="text/css" href="idpselect.css" />
</head>
<body>
<div id="idpSelect"></div>
<script src="idpselect_config.js" type="text/javascript" language="javascript"></script>
<script src="idpselect.js" type="text/javascript" language="javascript"></script>
<noscript>
<!-- If you need to care about non javascript browsers you will need to
generate a hyperlink to a non-js DS.
To build you will need:
- URL: The base URL of the DS you use
- EI: Your entityId, URLencoded. You can get this from the line that
this page is called with.
- RET: Your return address dlib-adidp.ucs.ed.ac.uk. Again you can get
this from the page this is called with, but beware of the
target%3Dcookie%253A5269905f bit..
< href=${URL}?entityID=${EI}&return=${RET}
-->
Your Browser does not support javascript. Please use
<a href="http://federation.org/DS/DS?entityID=https%3A%2F%2FyourentityId.edu.edu%2Fshibboleth&return=https%3A%2F%2Fyourreturn.edu%2FShibboleth.sso%2FDS%3FSAMLDS%3D1%26target%3Dhttps%3A%2F%2Fyourreturn.edu%2F">this link</a>.
</noscript>
</body>
</html>
function IdPSelectUI() {
//
// module locals
//
var idpData;
var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var idpSelectDiv;
var lang;
var majorLang;
var defaultLang;
var langBundle;
var defaultLangBundle;
var defaultLogo;
var defaultLogoWidth;
var defaultLogoHeight;
var minWidth;
var minHeight;
var maxWidth;
var maxHeight;
var bestRatio;
var doNotCollapse;
//
// Parameters passed into our closure
//
var preferredIdP;
var maxPreferredIdPs;
var helpURL;
var ie6Hack;
var samlIdPCookieTTL;
var maxIdPCharsDropDown;
var maxIdPCharsButton;
var maxIdPCharsAltTxt;
var alwaysShow;
var maxResults;
var ignoreKeywords;
var showListFirst;
var noWriteCookie;
var ignoreURLParams;
var autoFollowCookie;
var autoFollowCookieTTLs;
//
// The cookie contents
//
var userSelectedIdPs;
//
// Anchors used inside autofunctions
//
var idpEntryDiv;
var idpListDiv;
var idpSelect;
var listButton;
//
// local configuration
//
var idPrefix = 'idpSelect';
var classPrefix = 'IdPSelect';
var dropDownControl;
//
// DS protocol configuration
//
var returnString = '';
var returnBase='';
var returnParms= [];
var returnIDParam = 'entityID';
// *************************************
// Public functions
// *************************************
/**
Draws the IdP Selector UI on the screen. This is the main
method for the IdPSelectUI class.
*/
this.draw = function(parms){
if (!setupLocals(parms)) {
return;
}
idpSelectDiv = document.getElementById(parms.insertAtDiv);
if(!idpSelectDiv){
fatal(getLocalizedMessage('fatal.divMissing'));
return;
}
//
// Quick test for auto-dispatch
//
if ((null != autoFollowCookie) && (null != getCookieCalled( autoFollowCookie ))) {
var prefs = retrieveUserSelectedIdPs();
if (prefs.length != 0) {
var retString = returnIDParam + '=' + encodeURIComponent(prefs[0]);
//
// Compose up the URL
//
if (returnString.indexOf('?') == -1) {
retString = '?' + retString;
} else {
retString = '&' + retString;
}
//
// Go there
//
dispatchTo(idpSelectDiv, returnString + retString);
return;
}
}
if (!load(parms.dataSource)) {
return;
}
deDupe();
stripHidden(parms.hiddenIdPs);
idpData.sort(function(a,b) {return getLocalizedName(a).localeCompare(getLocalizedName(b));});
var idpSelector = buildIdPSelector();
idpSelectDiv.appendChild(idpSelector);
dropDownControl.draw(parms.setFocusTextBox);
} ;
// *************************************
// Private functions
//
// Data Manipulation
//
// *************************************
/**
Copies the "parameters" in the function into namesspace local
variables. This means most of the work is done outside the
IdPSelectUI object
*/
var setupLocals = function (paramsSupplied) {
//
// Copy parameters in
//
var suppliedEntityId;
preferredIdP = paramsSupplied.preferredIdP;
maxPreferredIdPs = paramsSupplied.maxPreferredIdPs;
helpURL = paramsSupplied.helpURL;
ie6Hack = paramsSupplied.ie6Hack;
samlIdPCookieTTL = paramsSupplied.samlIdPCookieTTL;
alwaysShow = paramsSupplied.alwaysShow;
maxResults = paramsSupplied.maxResults;
ignoreKeywords = paramsSupplied.ignoreKeywords;
if (paramsSupplied.showListFirst) {
showListFirst = paramsSupplied.showListFirst;
} else {
showListFirst = false;
}
if (paramsSupplied.noWriteCookie) {
noWriteCookie = paramsSupplied.noWriteCookie;
} else {
noWriteCookie = false;
}
if (paramsSupplied.ignoreURLParams) {
ignoreURLParams = paramsSupplied.ignoreURLParams;
} else {
ignoreURLParams = false;
}
defaultLogo = paramsSupplied.defaultLogo;
defaultLogoWidth = paramsSupplied.defaultLogoWidth;
defaultLogoHeight = paramsSupplied.defaultLogoHeight;
minWidth = paramsSupplied.minWidth;
minHeight = paramsSupplied.minHeight;
maxWidth = paramsSupplied.maxWidth;
maxHeight = paramsSupplied.maxHeight;
bestRatio = paramsSupplied.bestRatio;
if (null == paramsSupplied.doNotCollapse) {
doNotCollapse = true;
} else {
doNotCollapse = paramsSupplied.doNotCollapse;
}
maxIdPCharsButton = paramsSupplied.maxIdPCharsButton;
maxIdPCharsDropDown = paramsSupplied.maxIdPCharsDropDown;
maxIdPCharsAltTxt = paramsSupplied.maxIdPCharsAltTxt;
autoFollowCookie = paramsSupplied.autoFollowCookie;
autoFollowCookieTTLs = paramsSupplied.autoFollowCookieTTLs;
var lang;
if (typeof navigator == 'undefined') {
lang = paramsSupplied.defaultLanguage;
} else {
lang = navigator.language || navigator.userLanguage || paramsSupplied.defaultLanguage;
}
lang = lang.toLowerCase();
if (lang.indexOf('-') > 0) {
majorLang = lang.substring(0, lang.indexOf('-'));
}
var providedLangs = new IdPSelectLanguages();
defaultLang = paramsSupplied.defaultLanguage;
if (typeof paramsSupplied.langBundles != 'undefined' && typeof paramsSupplied.langBundles[lang] != 'undefined') {
langBundle = paramsSupplied.langBundles[lang];
} else if (typeof providedLangs.langBundles[lang] != 'undefined') {
langBundle = providedLangs.langBundles[lang];
} else if (typeof majorLang != 'undefined') {
if (typeof paramsSupplied.langBundles != 'undefined' && typeof paramsSupplied.langBundles[majorLang] != 'undefined') {
langBundle = paramsSupplied.langBundles[majorLang];
} else if (typeof providedLangs.langBundles[majorLang] != 'undefined') {
langBundle = providedLangs.langBundles[majorLang];
}
}
if (typeof paramsSupplied.langBundles != 'undefined' && typeof paramsSupplied.langBundles[paramsSupplied.defaultLanguage] != 'undefined') {
defaultLangBundle = paramsSupplied.langBundles[paramsSupplied.defaultLanguage];
} else {
defaultLangBundle = providedLangs.langBundles[paramsSupplied.defaultLanguage];
}
//
// Setup Language bundles
//
if (!defaultLangBundle) {
fatal('No languages work');
return false;
}
if (!langBundle) {
debug('No language support for ' + lang);
langBundle = defaultLangBundle;
}
if (paramsSupplied.testGUI) {
//
// no policing of parms
//
return true;
}
//
// Now set up the return values from the URL
//
var policy = 'urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single';
var i;
var isPassive = false;
var parms;
var parmPair;
var win = window;
while (null !== win.parent && win !== win.parent) {
win = win.parent;
}
var loc = win.location;
var parmlist = loc.search;
if (ignoreURLParams || null == parmlist || 0 == parmlist.length || parmlist.charAt(0) != '?') {
if ((null == paramsSupplied.defaultReturn)&& !ignoreURLParams) {
fatal(getLocalizedMessage('fatal.noparms'));
return false;
}
//
// No parameters, so just collect the defaults
//
suppliedEntityId = paramsSupplied.myEntityID;
returnString = paramsSupplied.defaultReturn;
if (null != paramsSupplied.defaultReturnIDParam) {
returnIDParam = paramsSupplied.defaultReturnIDParam;
}
} else {
parmlist = parmlist.substring(1);
//
// protect against various hideousness by decoding. We re-encode just before we push
//
parms = parmlist.split('&');
if (parms.length === 0) {
fatal(getLocalizedMessage('fatal.noparms'));
return false;
}
for (i = 0; i < parms.length; i++) {
parmPair = parms[i].split('=');
if (parmPair.length != 2) {
continue;
}
if (parmPair[0] == 'entityID') {
suppliedEntityId = decodeURIComponent(parmPair[1]);
} else if (parmPair[0] == 'return') {
returnString = decodeURIComponent(parmPair[1]);
} else if (parmPair[0] == 'returnIDParam') {
returnIDParam = decodeURIComponent(parmPair[1]);
} else if (parmPair[0] == 'policy') {
policy = decodeURIComponent(parmPair[1]);
} else if (parmPair[0] == 'isPassive') {
isPassive = (parmPair[1].toUpperCase() == "TRUE");
}
}
}
// Test protocol
var allowableProtocols;
if (null == paramsSupplied.allowableProtocols) {
allowableProtocols = ["urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"];
} else {
allowableProtocols = paramsSupplied.allowableProtocols;
}
var protocolOk = false;
for (var i = 0 ; i < allowableProtocols.length; i++) {
var protocol = allowableProtocols[i];
if (policy == protocol) {
protocolOk = true;
break;
}
}
if (!protocolOk) {
fatal(getLocalizedMessage('fatal.wrongProtocol'));
return false;
}
if (paramsSupplied.myEntityID !== null && paramsSupplied.myEntityID != suppliedEntityId) {
fatal(getLocalizedMessage('fatal.wrongEntityId') + '"' + suppliedEntityId + '" != "' + paramsSupplied.myEntityID + '"');
return false;
}
if (null === returnString || returnString.length === 0) {
fatal(getLocalizedMessage('fatal.noReturnURL'));
return false;
}
if (!validProtocol(returnString)) {
fatal(getLocalizedMessage('fatal.badProtocol'));
return false;
}
//
// isPassive
//
if (isPassive) {
var prefs = retrieveUserSelectedIdPs();
var parentDiv = document.getElementById(parmsSupplied.insertAtDiv);
if (prefs.length == 0) {
//
// no preference, go back
//
dispatchTo(parentDiv, returnString);
return false;
} else {
var retString = returnIDParam + '=' + encodeURIComponent(prefs[0]);
//
// Compose up the URL
//
if (returnString.indexOf('?') == -1) {
retString = '?' + retString;
} else {
retString = '&' + retString;
}
dispatchTo(parentDiv, returnString + retString);
return false;
}
}
//
// Now split up returnString
//
i = returnString.indexOf('?');
if (i < 0) {
returnBase = returnString;
return true;
}
returnBase = returnString.substring(0, i);
parmlist = returnString.substring(i+1);
parms = parmlist.split('&');
for (i = 0; i < parms.length; i++) {
parmPair = parms[i].split('=');
if (parmPair.length != 2) {
continue;
}
parmPair[1] = decodeURIComponent(parmPair[1]);
returnParms.push(parmPair);
}
return true;
};
/** Deduplicate by entityId */
var deDupe = function() {
var names = [];
var j;
for (j = 0; j < idpData.length; ) {
var eid = getEntityId(idpData[j]);
if (null == names[eid]) {
names[eid] = eid;
j = j + 1;
} else {
idpData.splice(j, 1);
}
}
}
/**
Strips the supllied IdP list from the idpData
*/
var stripHidden = function(hiddenList) {
if (null == hiddenList || 0 == hiddenList.length) {
return;
}
var i;
var j;
for (i = 0; i < hiddenList.length; i++) {
for (j = 0; j < idpData.length; j++) {
if (getEntityId(idpData[j]) == hiddenList[i]) {
idpData.splice(j, 1);
break;
}
}
}
}
/**
* Strip the "protocol://host" bit out of the URL and check the protocol
* @param the URL to process
* @return whether it starts with http: or https://
*/
var validProtocol = function(s) {
if (null === s) {
return false;
}
var marker = "://";
var protocolEnd = s.indexOf(marker);
if (protocolEnd < 0) {
return false;
}
s = s.substring(0, protocolEnd);
if (s == "http" || s== "https") {
return true;
}
return false;
};
/**
* We need to cache bust on IE. So how do we know? Use a bigger hammer.
*/
var isIE = function() {
if (null == navigator) {
return false;
}
var browserName = navigator.appName;
if (null == browserName) {
return false;
}
return (browserName == 'Microsoft Internet Explorer') ;
} ;
/**
* Alternative to location.href=string
*
* Needed to cache bust Firefox
*/
var dispatchTo = function(theParent, whereTo) {
var aval = document.createElement('a');
aval.href = whereTo;
theParent.appendChild(aval);
aval.click();
}
/**
Loads the data used by the IdP selection UI. Data is loaded
from a JSON document fetched from the given url.
@param {Function} failureCallback A function called if the JSON
document can not be loaded from the source. This function will
passed the {@link XMLHttpRequest} used to request the JSON data.
*/
var load = function(dataSource){
var xhr = null;
try {
xhr = new XMLHttpRequest();
} catch (e) {}
if (null == xhr) {
//
// EDS24. try to get 'Microsoft.XMLHTTP'
//
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
if (null == xhr) {
//
// EDS35. try to get 'Microsoft.XMLHTTP'
//
try {
xhr = new ActiveXObject('MSXML2.XMLHTTP.3.0');
} catch (e) {}
}
if (null == xhr) {
fatal(getLocalizedMessage('fatal.noXMLHttpRequest'));
return false;
}
if (isIE()) {
//
// cache bust (for IE)
//
dataSource += '?random=' + (Math.random()*1000000);
}
//
// Grab the data
//
xhr.open('GET', dataSource, false);
if (typeof xhr.overrideMimeType == 'function') {
xhr.overrideMimeType('application/json');
}
xhr.send(null);
if(xhr.status == 200){
//
// 200 means we got it OK from as web source
// if locally loading its 0. Go figure
//
var jsonData = xhr.responseText;
if(jsonData === null){
fatal(getLocalizedMessage('fatal.noData'));
return false;
}
//
// Parse it
//
idpData = JSON.parse(jsonData);
}else{
fatal(getLocalizedMessage('fatal.loadFailed') + dataSource);
return false;
}
return true;
};
/**
Returns the idp object with the given name.
@param (String) the name we are interested in
@return (Object) the IdP we care about
*/
var getIdPFor = function(idpName) {
for (var i = 0; i < idpData.length; i++) {
if (getEntityId(idpData[i]) == idpName) {
return idpData[i];
}
}
return null;
};
/**
Returns a suitable image from the given IdP
@param (Object) The IdP
@return Object) a DOM object suitable for insertion
TODO - rather more careful selection
*/
var getImageForIdP = function(idp, useDefault) {
var getBestFit = function(language) {
//
// See GetLocalizedEntry
//
var bestFit = null;
var i;
if (null == idp.Logos) {
return null;
}
for (i in idp.Logos) {
if (idp.Logos[i].lang == language &&
idp.Logos[i].width != null &&
idp.Logos[i].width >= minWidth &&
idp.Logos[i].height != null &&
idp.Logos[i].height >= minHeight) {
if (bestFit === null) {
bestFit = idp.Logos[i];
} else {
me = Math.abs(bestRatio - Math.log(idp.Logos[i].width/idp.Logos[i].height));
him = Math.abs(bestRatio - Math.log(bestFit.width/bestFit.height));
if (him > me) {
bestFit = idp.Logos[i];
}
}
}
}
return bestFit;
} ;
var bestFit = null;
var img = document.createElement('img');
setClass(img, 'IdPImg');
bestFit = getBestFit(lang);
if (null === bestFit && typeof majorLang != 'undefined') {
bestFit = getBestFit(majorLang);
}
if (null === bestFit) {
bestFit = getBestFit(null);
}
if (null === bestFit) {
bestFit = getBestFit(defaultLang);
}
if (null === bestFit) {
if (!useDefault) {
return null;
}
img.src = defaultLogo;
img.width = defaultLogoWidth;
img.height = defaultLogoHeight;
img.alt = getLocalizedMessage('defaultLogoAlt');
return img;
}
img.src = bestFit.value;
var altTxt = getLocalizedName(idp);
if (altTxt.length > maxIdPCharsAltTxt) {
altTxt = altTxt.substring(0, maxIdPCharsAltTxt) + '...';
}
img.alt = altTxt;
var w = bestFit.width;
var h = bestFit.height;
if (w>maxWidth) {
h = (maxWidth/w) * h;
w = maxWidth;
}
if (h> maxHeight) {
w = (maxHeight/h) * w;
h = maxHeight;
}
img.setAttribute('width', w);
img.setAttribute('height', h);
return img;
};
// *************************************
// Private functions
//
// GUI Manipulation
//
// *************************************
/**
Builds the IdP selection UI.
Three divs. PreferredIdPTime, EntryTile and DropdownTile
Optional div AutoDispatchPane
@return {Element} IdP selector UI
*/
var buildIdPSelector = function(){
var containerDiv = buildDiv('IdPSelector');
var preferredTileExists;
preferredTileExists = buildPreferredIdPTile(containerDiv);
buildIdPEntryTile(containerDiv, preferredTileExists);
buildIdPDropDownListTile(containerDiv, preferredTileExists);
if (null != autoFollowCookie) {
buildAutoDispatchPane(containerDiv);
}
return containerDiv;
};
/**
Builds a button for the provided IdP
<div class="preferredIdPButton">
<a href="XYX" onclick=setparm('ABCID')>
<div class=
<img src="https:\\xyc.gif"> <!-- optional -->
XYX Text
</a>
</div>
@param (Object) The IdP
@return (Element) preselector for the IdP
*/
var composePreferredIdPButton = function(idp, uniq, useDefault) {
var div = buildDiv(undefined, 'PreferredIdPButton');
var aval = document.createElement('a');
var retString = returnIDParam + '=' + encodeURIComponent(getEntityId(idp));
var retVal = returnString;
var img = getImageForIdP(idp, useDefault);
//
// Compose up the URL
//
if (retVal.indexOf('?') == -1) {
retString = '?' + retString;
} else {
retString = '&' + retString;
}
aval.href = retVal + retString;
aval.onclick = function () {
selectIdP(getEntityId(idp));
};
if (null != img) {
var imgDiv=buildDiv(undefined, 'PreferredIdPImg');
imgDiv.appendChild(img);
aval.appendChild(imgDiv);
}
var nameDiv = buildDiv(undefined, 'TextDiv');
var nameStr = getLocalizedName(idp);
if (nameStr.length > maxIdPCharsButton) {
nameStr = nameStr.substring(0, maxIdPCharsButton) + '...';
}
div.title = nameStr;
nameDiv.appendChild(document.createTextNode(nameStr));
aval.appendChild(nameDiv);
div.appendChild(aval);
return div;
};
/**
* Builds and populated a text Div
*/
var buildTextDiv = function(parent, textId)
{
var div = buildDiv(undefined, 'TextDiv');
var introTxt = document.createTextNode(getLocalizedMessage(textId));
div.appendChild(introTxt);
parent.appendChild(div);
} ;
var setSelector = function (selector, selected) {
if (null === selected || 0 === selected.length || '-' == selected.value) {
return;
}
var i = 0;
while (i < selector.options.length) {
if (selector.options[i].value == selected) {
selector.options[i].selected = true;
break;
}
i++;
}
}
/**
Builds the preferred IdP selection UI (top half of the UI w/ the
IdP buttons)
<div id=prefix+"PreferredIdPTile">
<div> [see comprosePreferredIdPButton </div>
[repeated]
</div>
@return {Element} preferred IdP selection UI
*/
var buildPreferredIdPTile = function(parentDiv) {
var preferredIdPs = getPreferredIdPs();
if (0 === preferredIdPs.length) {
return false;
}
var atLeastOneImg = doNotCollapse;
for(var i = 0 ; i < maxPreferredIdPs && i < preferredIdPs.length; i++){
if (preferredIdPs[i] && getImageForIdP(preferredIdPs[i], false)) {
atLeastOneImg = true;
}
}
var preferredIdPDIV;
if (atLeastOneImg) {
preferredIdPDIV = buildDiv('PreferredIdPTile');
} else {
preferredIdPDIV = buildDiv('PreferredIdPTileNoImg');
}
buildTextDiv(preferredIdPDIV, 'idpPreferred.label');
for(var i = 0 ; i < maxPreferredIdPs && i < preferredIdPs.length; i++){
if (preferredIdPs[i]) {
var button = composePreferredIdPButton(preferredIdPs[i],i, atLeastOneImg);
preferredIdPDIV.appendChild(button);
}
}
parentDiv.appendChild(preferredIdPDIV);
return true;
};
/**
* Build the <form> from the return parameters
*/
var buildSelectForm = function ()
{
var form = document.createElement('form');
idpEntryDiv.appendChild(form);
form.action = returnBase;
form.method = 'GET';
form.setAttribute('autocomplete', 'OFF');
var i = 0;
for (i = 0; i < returnParms.length; i++) {
var hidden = document.createElement('input');
hidden.setAttribute('type', 'hidden');
hidden.name = returnParms[i][0];
hidden.value= returnParms[i][1];
form.appendChild(hidden);
}
return form;
} ;
/**
Build the manual IdP Entry tile (bottom half of UI with
search-as-you-type field).
<div id = prefix+"IdPEntryTile">
<form>
<input type="text", id=prefix+"IdPSelectInput/> // select text box
<input type="hidden" /> param to send
<input type="submit" />
@return {Element} IdP entry UI tile
*/
var buildIdPEntryTile = function(parentDiv, preferredTile) {
idpEntryDiv = buildDiv('IdPEntryTile');
if (showListFirst) {
idpEntryDiv.style.display = 'none';
}
var label = document.createElement('label');
label.setAttribute('for', idPrefix + 'Input');
if (preferredTile) {
buildTextDiv(label, 'idpEntry.label');
} else {
buildTextDiv(label, 'idpEntry.NoPreferred.label');
}
var form = buildSelectForm();
form.appendChild(label);
var textInput = document.createElement('input');
form.appendChild(textInput);
textInput.type='text';
setID(textInput, 'Input');
var hidden = document.createElement('input');
hidden.setAttribute('type', 'hidden');
form.appendChild(hidden);
hidden.name = returnIDParam;
hidden.value='-';
var button = buildContinueButton('Select');
button.disabled = true;
form.appendChild(button);
form.onsubmit = function () {
//
// Make sure we cannot ask for garbage
//
if (null === hidden.value || 0 === hidden.value.length || '-' == hidden.value) {
return false;
}
//
// And always ask for the cookie to be updated before we continue
//
textInput.value = hidden.textValue;
selectIdP(hidden.value);
return true;
};
dropDownControl = new TypeAheadControl(idpData, textInput, hidden, button, maxIdPCharsDropDown, getLocalizedName, getEntityId, geticon, ie6Hack, alwaysShow, maxResults, getKeywords);
var a = document.createElement('a');
a.appendChild(document.createTextNode(getLocalizedMessage('idpList.showList')));
a.href = '#';
setClass(a, 'DropDownToggle');
a.onclick = function() {
idpEntryDiv.style.display='none';
setSelector(idpSelect, hidden.value);
idpListDiv.style.display='';
listButton.focus();
return false;
};
idpEntryDiv.appendChild(a);
buildHelpText(idpEntryDiv);
parentDiv.appendChild(idpEntryDiv);
};
/**
Builds the drop down list containing all the IdPs from which a
user may choose.
<div id=prefix+"IdPListTile">
<label for="idplist">idpList.label</label>
<form action="URL from IDP Data" method="GET">
<select name="param from IdP data">
<option value="EntityID">Localized Entity Name</option>
[...]
</select>
<input type="submit"/>
</div>
@return {Element} IdP drop down selection UI tile
*/
var buildIdPDropDownListTile = function(parentDiv, preferredTile) {
idpListDiv = buildDiv('IdPListTile');
if (!showListFirst) {
idpListDiv.style.display = 'none';
}
var label = document.createElement('label');
label.setAttribute('for', idPrefix + 'Selector');
if (preferredTile) {
buildTextDiv(label, 'idpList.label');
} else {
buildTextDiv(label, 'idpList.NoPreferred.label');
}
idpSelect = document.createElement('select');
setID(idpSelect, 'Selector');
idpSelect.name = returnIDParam;
idpListDiv.appendChild(idpSelect);
var idpOption = buildSelectOption('-', getLocalizedMessage('idpList.defaultOptionLabel'));
idpOption.selected = true;
idpSelect.appendChild(idpOption);
var idp;
for(var i=0; i<idpData.length; i++){
idp = idpData[i];
idpOption = buildSelectOption(getEntityId(idp), getLocalizedName(idp));
idpSelect.appendChild(idpOption);
}
var form = buildSelectForm();
form.appendChild(label);
form.appendChild(idpSelect);
form.onsubmit = function () {
//
// The first entery isn't selectable
//
if (idpSelect.selectedIndex < 1) {
return false;
}
//
// otherwise update the cookie
//
selectIdP(idpSelect.options[idpSelect.selectedIndex].value);
return true;
};
var button = buildContinueButton('List');
listButton = button;
form.appendChild(button);
idpListDiv.appendChild(form);
//
// The switcher
//
var a = document.createElement('a');
a.appendChild(document.createTextNode(getLocalizedMessage('idpList.showSearch')));
a.href = '#';
setClass(a, 'DropDownToggle');
a.onclick = function() {
idpEntryDiv.style.display='';
idpListDiv.style.display='none';
return false;
};
idpListDiv.appendChild(a);
buildHelpText(idpListDiv);
parentDiv.appendChild(idpListDiv);
};
var buildAutoDispatchPane = function(parent) {
var inputName = 'IdPSelectAutoDisp'
autoDispatchTile = buildDiv(undefined, 'autoDispatchArea');
autoDispatchTile.appendChild(document.createTextNode(getLocalizedMessage('autoFollow.message')));
//
// The "clear" button
//
var but = document.createElement('input');
but.setAttribute('type', 'radio');
but.setAttribute('checked', 'checked');
but.setAttribute('name', inputName);
but.onclick = function () {
setAutoDispatchCookie(0);
}
div = buildDiv(undefined, 'autoDispatchTile');
div.appendChild(but);
div.appendChild(document.createTextNode(getLocalizedMessage('autoFollow.never')));
autoDispatchTile.appendChild(div);
var i;
for (i = 0; i < autoFollowCookieTTLs.length; i++) {
//
// The timed buttons
//
but = document.createElement('input');
but.setAttribute('type', 'radio');
but.setAttribute('name', inputName);
but.life = autoFollowCookieTTLs[i];
but.onclick = function () {
var f = this.life;
setAutoDispatchCookie(f);
}
div = buildDiv(undefined, 'autoDispatchTile');
div.appendChild(but);
div.appendChild(document.createTextNode(
getLocalizedMessage('autoFollow.time'+i)));
autoDispatchTile.appendChild(div);
}
parent.appendChild(autoDispatchTile);
}
/**
Builds the 'continue' button used to submit the IdP selection.
@return {Element} HTML button used to submit the IdP selection
*/
var buildContinueButton = function(which) {
var button = document.createElement('input');
button.setAttribute('type', 'submit');
button.value = getLocalizedMessage('submitButton.label');
setID(button, which + 'Button');
return button;
};
/**
Builds an aref to point to the helpURL
*/
var buildHelpText = function(containerDiv) {
var aval = document.createElement('a');
aval.href = helpURL;
aval.appendChild(document.createTextNode(getLocalizedMessage('helpText')));
setClass(aval, 'HelpButton');
containerDiv.appendChild(aval);
} ;
/**
Creates a div element whose id attribute is set to the given ID.
@param {String} id ID for the created div element
@param {String} [class] class of the created div element
@return {Element} DOM 'div' element with an 'id' attribute
*/
var buildDiv = function(id, whichClass){
var div = document.createElement('div');
if (undefined !== id) {
setID(div, id);
}
if(undefined !== whichClass) {
setClass(div, whichClass);
}
return div;
};
/**
Builds an HTML select option element
@param {String} value value of the option when selected
@param {String} label displayed label of the option
*/
var buildSelectOption = function(value, text){
var option = document.createElement('option');
option.value = value;
if (text.length > maxIdPCharsDropDown) {
text = text.substring(0, maxIdPCharsDropDown);
}
option.appendChild(document.createTextNode(text));
return option;
};
/**
Sets the attribute 'id' on the provided object
We do it through this function so we have a single
point where we can prepend a value
@param (Object) The [DOM] Object we want to set the attribute on
@param (String) The Id we want to set
*/
var setID = function(obj, name) {
obj.id = idPrefix + name;
};
var setClass = function(obj, name) {
obj.setAttribute('class', classPrefix + name);
};
/**
Returns the DOM object with the specified id. We abstract
through a function to allow us to prepend to the name
@param (String) the (unprepended) id we want
*/
var locateElement = function(name) {
return document.getElementById(idPrefix + name);
};
// *************************************
// Private functions
//
// GUI actions. Note that there is an element of closure going on
// here since these names are invisible outside this module.
//
//
// *************************************
/**
* Base helper function for when an IdP is selected
* @param (String) The UN-encoded entityID of the IdP
*/
var selectIdP = function(idP) {
updateSelectedIdPs(idP);
saveUserSelectedIdPs(userSelectedIdPs);
};
// *************************************
// Private functions
//
// Localization handling
//
// *************************************
/**
Gets a localized string from the given language pack. This
method uses the {@link langBundles} given during construction
time.
@param {String} messageId ID of the message to retrieve
@return (String) the message
*/
var getLocalizedMessage = function(messageId){
var message = langBundle[messageId];
if(!message){
message = defaultLangBundle[messageId];
}
if(!message){
message = 'Missing message for ' + messageId;
}
return message;
};
var getEntityId = function(idp) {
return idp.entityID;
};
/**
Returns the icon information for the provided idp
@param (Object) an idp. This should have an array 'names' with sub
elements 'lang' and 'name'.
@return (String) The localized name
*/
var geticon = function(idp) {
var i;
if (null == idp.Logos) {
return null;
}
for (i =0; i < idp.Logos.length; i++) {
var logo = idp.Logos[i];
if (logo.height == "16" && logo.width == "16") {
if (null == logo.lang ||
lang == logo.lang ||
(typeof majorLang != 'undefined' && majorLang == logo.lang) ||
defaultLang == logo.lang) {
return logo.value;
}
}
}
return null;
} ;
/**
Returns the localized name information for the provided idp
@param (Object) an idp. This should have an array 'names' with sub
elements 'lang' and 'name'.
@return (String) The localized name
*/
var getLocalizedName = function(idp) {
var res = getLocalizedEntry(idp.DisplayNames);
if (null !== res) {
return res;
}
debug('No Name entry in any language for ' + getEntityId(idp));
return getEntityId(idp);
} ;
var getKeywords = function(idp) {
if (ignoreKeywords || null == idp.Keywords) {
return null;
}
var s = getLocalizedEntry(idp.Keywords);
return s;
}
var getLocalizedEntry = function(theArray){
var i;
//
// try by full name
//
for (i in theArray) {
if (theArray[i].lang == lang) {
return theArray[i].value;
}
}
//
// then by major language
//
if (typeof majorLang != 'undefined') {
for (i in theArray) {
if (theArray[i].lang == majorLang) {
return theArray[i].value;
}
}
}
//
// then by null language in metadata
//
for (i in theArray) {
if (theArray[i].lang == null) {
return theArray[i].value;
}
}
//
// then by default language
//
for (i in theArray) {
if (theArray[i].lang == defaultLang) {
return theArray[i].value;
}
}
return null;
};
// *************************************
// Private functions
//
// Cookie and preferred IdP Handling
//
// *************************************
/**
Gets the preferred IdPs. The first elements in the array will
be the preselected preferred IdPs. The following elements will
be those past IdPs selected by a user. The size of the array
will be no larger than the maximum number of preferred IdPs.
*/
var getPreferredIdPs = function() {
var idps = [];
var offset = 0;
var i;
var j;
//
// populate start of array with preselected IdPs
//
if(null != preferredIdP){
for(i=0; i < preferredIdP.length && i < maxPreferredIdPs; i++){
idps[i] = getIdPFor(preferredIdP[i]);
offset++;
}
}
//
// And then the cookie based ones
//
userSelectedIdPs = retrieveUserSelectedIdPs();
for (i = offset, j=0; j < userSelectedIdPs.length && i < maxPreferredIdPs; j++){
var cur_idp = getIdPFor(userSelectedIdPs[j]);
if (typeof idps.indexOf === 'undefined') {
idps.push(cur_idp);
i++;
}
else if (idps.indexOf(cur_idp) === -1) {
idps.push(cur_idp);
i++;
}
}
return idps;
};
/**
Update the userSelectedIdPs list with the new value.
@param (String) the newly selected IdP
*/
var updateSelectedIdPs = function(newIdP) {
//
// We cannot use split since it does not appear to
// work as per spec on ie8.
//
var newList = [];
//
// iterate through the list copying everything but the old
// name
//
while (0 !== userSelectedIdPs.length) {
var what = userSelectedIdPs.pop();
if (what != newIdP) {
newList.unshift(what);
}
}
//
// And shove it in at the top
//
newList.unshift(newIdP);
userSelectedIdPs = newList;
return;
};
/*
Set the autoFollowCookie with a life of the specified number of days
or clear it.
@parm (integer) days The cookie lifetime if >0. If <=0 clear cookie
*/
var setAutoDispatchCookie = function(days) {
var expireDate;
if(days > 0){
var now = new Date();
cookieTTL = days * 24 * 60 * 60 * 1000;
expireDate = new Date(now.getTime() + cookieTTL);
} else {
expireDate = new Date(0);
}
document.cookie=autoFollowCookie + '=1;path=/;expires=' + expireDate.toUTCString();
}
/**
Gets the value of the cookie with the provided name
@param (string) name - the name to look for
@return the value or null if no cookie of that name
*/
var getCookieCalled = function (name) {
var i, j;
var cookies;
cookies = document.cookie.split( ';' );
for (i = 0; i < cookies.length; i++) {
//
// Do not use split('='), '=' is valid in Base64 encoding!
//
var cookie = cookies[i];
var splitPoint = cookie.indexOf( '=' );
var cookieName = cookie.substring(0, splitPoint);
if ( name == ( cookieName.replace(/^\s+|\s+$/g, ''))) {
return cookie.substring(splitPoint+1);
}
}
return null;
}
/**
Gets the IdP previously selected by the user.
@return {Array} user selected IdPs identified by their entity ID
*/
var retrieveUserSelectedIdPs = function(){
var userSelectedIdPs = [];
var j;
var cookieValues = getCookieCalled( '_saml_idp' );
if ( cookieValues != null) {
cookieValues = cookieValues.replace(/^\s+|\s+$/g, '');
cookieValues = cookieValues.replace('+','%20');
cookieValues = cookieValues.split('%20');
for(j=cookieValues.length; j > 0; j--){
if (0 === cookieValues[j-1].length) {
continue;
}
var dec = base64Decode(decodeURIComponent(cookieValues[j-1]));
if (dec.length > 0) {
userSelectedIdPs.push(dec);
}
}
}
return userSelectedIdPs;
};
/**
Saves the IdPs selected by the user.
@param {Array} idps idps selected by the user
*/
var saveUserSelectedIdPs = function(idps){
var cookieData = [];
var length = idps.length;
if (noWriteCookie) {
return;
}
if (length > 5) {
length = 5;
}
for(var i=length; i > 0; i--){
if (idps[i-1].length > 0) {
cookieData.push(encodeURIComponent(base64Encode(idps[i-1])));
}
}
var expireDate = null;
if(samlIdPCookieTTL){
var now = new Date();
cookieTTL = samlIdPCookieTTL * 24 * 60 * 60 * 1000;
expireDate = new Date(now.getTime() + cookieTTL);
}
document.cookie='_saml_idp' + '=' + cookieData.join('%20') + '; path = /' +
((expireDate===null) ? '' : '; expires=' + expireDate.toUTCString());
};
/**
Base64 encodes the given string.
@param {String} input string to be encoded
@return {String} base64 encoded string
*/
var base64Encode = function(input) {
var output = '', c1, c2, c3, e1, e2, e3, e4;
for ( var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
c2 = input.charCodeAt(i++);
c3 = input.charCodeAt(i++);
e1 = c1 >> 2;
e2 = ((c1 & 3) << 4) + (c2 >> 4);
e3 = ((c2 & 15) << 2) + (c3 >> 6);
e4 = c3 & 63;
if (isNaN(c2)){
e3 = e4 = 64;
} else if (isNaN(c3)){
e4 = 64;
}
output += base64chars.charAt(e1) +
base64chars.charAt(e2) +
base64chars.charAt(e3) +
base64chars.charAt(e4);
}
return output;
};
/**
Base64 decodes the given string.
@param {String} input string to be decoded
@return {String} base64 decoded string
*/
var base64Decode = function(input) {
var output = '', chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
// Remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
do {
enc1 = base64chars.indexOf(input.charAt(i++));
enc2 = base64chars.indexOf(input.charAt(i++));
enc3 = base64chars.indexOf(input.charAt(i++));
enc4 = base64chars.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = '';
enc1 = enc2 = enc3 = enc4 = '';
} while (i < input.length);
return output;
};
// *************************************
// Private functions
//
// Error Handling. we'll keep it separate with a view to eventual
// exbedding into log4js
//
// *************************************
/**
*/
var fatal = function(message) {
alert('FATAL - DISCO UI:' + message);
var txt = document.createTextNode(message);
idpSelectDiv.appendChild(txt);
};
var debug = function() {
//
// Nothing
};
}
(new IdPSelectUI()).draw(new IdPSelectUIParms());
/** @class IdP Selector UI */
function IdPSelectUIParms(){
//
// Adjust the following to fit into your local configuration
//
this.alwaysShow = true; // If true, this will show results as soon as you start typing
this.dataSource = '/Shibboleth.sso/DiscoFeed'; // Where to get the data from
this.defaultLanguage = 'en'; // Language to use if the browser local doesnt have a bundle
this.defaultLogo = 'blank.gif'; // Replace with your own logo
this.defaultLogoWidth = 1;
this.defaultLogoHeight = 1 ;
this.defaultReturn = null; // If non null, then the default place to send users who are not
// Approaching via the Discovery Protocol for example
//this.defaultReturn = "https://example.org/Shibboleth.sso/DS?SAMLDS=1&target=https://example.org/secure";
this.defaultReturnIDParam = null;
this.helpURL = 'https://wiki.shibboleth.net/confluence/display/SHIB2/DSRoadmap';
this.ie6Hack = null; // An array of structures to disable when drawing the pull down (needed to
// handle the ie6 z axis problem
this.insertAtDiv = 'idpSelect'; // The div where we will insert the data
this.maxResults = 10; // How many results to show at once or the number at which to
// start showing if alwaysShow is false
this.myEntityID = null; // If non null then this string must match the string provided in the DS parms
this.preferredIdP = null; // Array of entityIds to always show
this.hiddenIdPs = null; // Array of entityIds to delete
this.ignoreKeywords = false; // Do we ignore the <mdui:Keywords/> when looking for candidates
this.showListFirst = false; // Do we start with a list of IdPs or just the dropdown
this.samlIdPCookieTTL = 730; // in days
this.setFocusTextBox = true; // Set to false to supress focus
this.testGUI = false;
this.autoFollowCookie = null; // If you want auto-dispatch, set this to the cookie name to use
this.autoFollowCookieTTLs = [ 1, 60, 270 ]; // Cookie life (in days). Changing this requires changes to idp_select_languages
//
// Language support.
//
// The minified source provides "en", "de", "pt-br" and "jp".
//
// Override any of these below, or provide your own language
//
//this.langBundles = {
//'en': {
// 'fatal.divMissing': '<div> specified as "insertAtDiv" could not be located in the HTML',
// 'fatal.noXMLHttpRequest': 'Browser does not support XMLHttpRequest, unable to load IdP selection data',
// 'fatal.wrongProtocol' : 'Policy supplied to DS was not "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',
// 'fatal.wrongEntityId' : 'entityId supplied by SP did not match configuration',
// 'fatal.noData' : 'Metadata download returned no data',
// 'fatal.loadFailed': 'Failed to download metadata from ',
// 'fatal.noparms' : 'No parameters to discovery session and no defaultReturn parameter configured',
// 'fatal.noReturnURL' : "No URL return parameter provided",
// 'fatal.badProtocol' : "Return request must start with https:// or http://",
// 'idpPreferred.label': 'Use a suggested selection:',
// 'idpEntry.label': 'Or enter your organization\'s name',
// 'idpEntry.NoPreferred.label': 'Enter your organization\'s name',
// 'idpList.label': 'Or select your organization from the list below',
// 'idpList.NoPreferred.label': 'Select your organization from the list below',
// 'idpList.defaultOptionLabel': 'Please select your organization...',
// 'idpList.showList' : 'Allow me to pick from a list',
// 'idpList.showSearch' : 'Allow me to specify the site',
// 'submitButton.label': 'Continue',
// 'helpText': 'Help',
// 'defaultLogoAlt' : 'DefaultLogo'
//}
//};
//
// The following should not be changed without changes to the css. Consider them as mandatory defaults
//
this.maxPreferredIdPs = 3;
this.maxIdPCharsButton = 33;
this.maxIdPCharsDropDown = 58;
this.maxIdPCharsAltTxt = 60;
this.minWidth = 20;
this.minHeight = 20;
this.maxWidth = 115;
this.maxHeight = 69;
this.bestRatio = Math.log(80 / 60);
}
/** @class IdP Selector UI */
function IdPSelectLanguages(){
//
// Globalization stuff
//
this.langBundles = {
'en': {
'fatal.divMissing': '<div> specified as "insertAtDiv" could not be located in the HTML',
'fatal.noXMLHttpRequest': 'Browser does not support XMLHttpRequest, unable to load IdP selection data',
'fatal.wrongProtocol' : 'Policy supplied to DS was not "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',
'fatal.wrongEntityId' : 'entityId supplied by SP did not match configuration',
'fatal.noData' : 'Metadata download returned no data',
'fatal.loadFailed': 'Failed to download metadata from ',
'fatal.noparms' : 'No parameters to discovery session and no defaultReturn parameter configured',
'fatal.noReturnURL' : "No URL return parameter provided",
'fatal.badProtocol' : "Return request must start with https:// or http://",
'idpPreferred.label': 'Use a suggested selection:',
'idpEntry.label': 'Or enter your organization\'s name',
'idpEntry.NoPreferred.label': 'Enter your organization\'s name',
'idpList.label': 'Or select your organization from the list below',
'idpList.NoPreferred.label': 'Select your organization from the list below',
'idpList.defaultOptionLabel': 'Please select your organization...',
'idpList.showList' : 'Allow me to pick from a list',
'idpList.showSearch' : 'Allow me to specify the site',
'submitButton.label': 'Continue',
'helpText': 'Help',
'defaultLogoAlt' : 'DefaultLogo',
'autoFollow.message' : 'Always follows this selection',
'autoFollow.never' : 'Never',
'autoFollow.time0' : 'One day',
'autoFollow.time1' : '3 months',
'autoFollow.time2' : '9 months'
},
'de': {
'fatal.divMissing': 'Das notwendige Div Element fehlt',
'fatal.noXMLHttpRequest': 'Ihr Webbrowser unterst\u00fctzt keine XMLHttpRequests, IdP-Auswahl kann nicht geladen werden',
'fatal.wrongProtocol' : 'DS bekam eine andere Policy als "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',
'fatal.wrongEntityId' : 'Die entityId ist nicht korrekt',
'fatal.loadFailed': 'Metadaten konnten nicht heruntergeladen werden: ',
'fatal.noparms' : 'Parameter f\u00fcr das Discovery Service oder \'defaultReturn\' fehlen',
'fatal.noReturnURL' : "URL return Parmeter fehlt",
'fatal.badProtocol' : "return Request muss mit https:// oder http:// beginnen",
'idpPreferred.label': 'Vorherige Auswahl:',
'idpEntry.label': 'Oder geben Sie den Namen (oder Teile davon) an:',
'idpEntry.NoPreferred.label': 'Namen (oder Teile davon) der Institution angeben:',
'idpList.label': 'Oder w\u00e4hlen Sie Ihre Institution aus einer Liste:',
'idpList.NoPreferred.label': 'Institution aus folgender Liste w\u00e4hlen:',
'idpList.defaultOptionLabel': 'W\u00e4hlen Sie Ihre Institution aus...',
'idpList.showList' : 'Institution aus einer Liste w\u00e4hlen',
'idpList.showSearch' : 'Institution selbst angeben',
'submitButton.label': 'OK',
'helpText': 'Hilfe',
'defaultLogoAlt' : 'Standard logo'
},
'ja': {
'fatal.divMissing': '"insertAtDiv" の ID を持つ <div> が HTML 中に存在しません',
'fatal.noXMLHttpRequest': 'ブラウザが XMLHttpRequest をサポートしていないので IdP 情報を取得できません',
'fatal.wrongProtocol' : 'DSへ渡された Policy パラメータが "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single" ではありません',
'fatal.wrongEntityId' : 'SP から渡された entityId が設定値と異なります',
'fatal.noData' : 'メタデータが空です',
'fatal.loadFailed': '次の URL からメタデータをダウンロードできませんでした: ',
'fatal.noparms' : 'DSにパラメータが渡されておらず defaultReturn も設定されていません',
'fatal.noReturnURL' : "戻り URL が指定されていません",
'fatal.badProtocol' : "戻り URL は https:// か http:// で始まらなければなりません",
'idpPreferred.label': '選択候補の IdP:',
'idpEntry.label': 'もしくはあなたの所属機関名を入力してください',
'idpEntry.NoPreferred.label': 'あなたの所属機関名を入力してください',
'idpList.label': 'もしくはあなたの所属機関を選択してください',
'idpList.NoPreferred.label': 'あなたの所属機関を一覧から選択してください',
'idpList.defaultOptionLabel': '所属機関を選択してください...',
'idpList.showList' : '一覧から選択する',
'idpList.showSearch' : '機関名を入力する',
'submitButton.label': '選択',
'autoFollow.message' : '次の期間選択した機関に自動的に遷移する:',
'autoFollow.never' : '自動遷移しない',
'autoFollow.time0' : '1日',
'autoFollow.time1' : '3か月',
'autoFollow.time2' : '9か月',
'helpText': 'Help',
'defaultLogoAlt' : 'DefaultLogo'
},
'pt-br': {
'fatal.divMissing': 'A tag <div> com "insertAtDiv" não foi encontrada no arquivo HTML',
'fatal.noXMLHttpRequest': 'Seu navegador não suporta "XMLHttpRequest", impossível de carregador os dados do IdP selecionado',
'fatal.wrongProtocol' : 'A política "Policy" fornecida para o DS não foi "urn:oasis:names:tc:SAML:profiles:SSO:idpdiscovery-protocol:single"',
'fatal.wrongEntityId' : 'entityId oferecido pelo SP não confere com o da configuração',
'fatal.noData' : 'O arquivo de metadados não retornou nada;',
'fatal.loadFailed': 'Falhou ao realizar download do metadado de ',
'fatal.noparms' : 'Sem parâmetros para sessão de descoberta e sem parâmetro "defaultReturn" configurado',
'fatal.noReturnURL' : "Não foi definida um endereço (URL) de retorno no parâmetro",
'fatal.badProtocol' : "Retorno do endereço requisitado deve começar com https:// ou http://",
'idpPreferred.label': 'Use estas Instituições sugeridas: ',
'idpEntry.label': 'Ou informe o nome da sua Instituição',
'idpEntry.NoPreferred.label': 'Informe o nome da sua Instituição',
'idpList.label': 'Ou selecione sua Instituição através da lista abaixo',
'idpList.NoPreferred.label': 'Selecione sua Instituição através da lista abaixo',
'idpList.defaultOptionLabel': 'Por favor, selecione sua Instituição: ',
'idpList.showList' : 'Permitir que eu escolha um IdP através de uma lista',
'idpList.showSearch' : 'Permitir que eu especifique o IdP',
'submitButton.label': 'Continuar ',
'helpText': 'Ajuda',
'defaultLogoAlt' : 'Logo padrão'
}
};
}
/*
http://www.JSON.org/json2.js
2011-02-23
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' : gap ?
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' : gap ?
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
'{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
function TypeAheadControl(jsonObj, box, orig, submit, maxchars, getName, getEntityId, geticon, ie6hack, alwaysShow, maxResults, getKeywords)
{
//
// Squirrel away the parameters we were given
//
this.elementList = jsonObj;
this.textBox = box;
this.origin = orig;
this.submit = submit;
this.results = 0;
this.alwaysShow = alwaysShow;
this.maxResults = maxResults;
this.ie6hack = ie6hack;
this.maxchars = maxchars;
this.getName = getName;
this.getEntityId = getEntityId;
this.geticon = geticon;
this.getKeywords = getKeywords;
}
TypeAheadControl.prototype.draw = function(setFocus) {
//
// Make a closure on this so that the embedded functions
// get access to it.
//
var myThis = this;
//
// Set up the 'dropDown'
//
this.dropDown = document.createElement('ul');
this.dropDown.className = 'IdPSelectDropDown';
this.dropDown.style.visibility = 'hidden';
this.dropDown.style.width = this.textBox.offsetWidth;
this.dropDown.current = -1;
this.textBox.setAttribute('role', 'listbox');
document.body.appendChild(this.dropDown);
//
// Set ARIA on the input
//
this.textBox.setAttribute('role', 'combobox');
this.textBox.setAttribute('aria-controls', 'IdPSelectDropDown');
this.textBox.setAttribute('aria-owns', 'IdPSelectDropDown');
//
// mouse listeners for the dropdown box
//
this.dropDown.onmouseover = function(event) {
if (!event) {
event = window.event;
}
var target;
if (event.target){
target = event.target;
}
if (typeof target == 'undefined') {
target = event.srcElement;
}
myThis.select(target);
};
this.dropDown.onmousedown = function(event) {
if (-1 != myThis.dropDown.current) {
myThis.textBox.value = myThis.results[myThis.dropDown.current][0];
}
};
//
// Add the listeners to the text box
//
this.textBox.onkeyup = function(event) {
//
// get window event if needed (because of browser oddities)
//
if (!event) {
event = window.event;
}
myThis.handleKeyUp(event);
};
this.textBox.onkeydown = function(event) {
if (!event) {
event = window.event;
}
myThis.handleKeyDown(event);
};
this.textBox.onblur = function() {
myThis.hideDrop();
};
this.textBox.onfocus = function() {
myThis.handleChange();
};
if (null == setFocus || setFocus) {
this.textBox.focus();
}
};
//
// Given a name return the first maxresults, or all possibles
//
TypeAheadControl.prototype.getPossible = function(name) {
var possibles = [];
var inIndex = 0;
var outIndex = 0;
var strIndex = 0;
var str;
var ostr;
name = name.toLowerCase();
while (outIndex <= this.maxResults && inIndex < this.elementList.length) {
var hit = false;
var thisName = this.getName(this.elementList[inIndex]);
//
// Check name
//
if (thisName.toLowerCase().indexOf(name) != -1) {
hit = true;
}
//
// Check entityID
//
if (!hit && this.getEntityId(this.elementList[inIndex]).toLowerCase().indexOf(name) != -1) {
hit = true;
}
if (!hit) {
var thisKeywords = this.getKeywords(this.elementList[inIndex]);
if (null != thisKeywords &&
thisKeywords.toLowerCase().indexOf(name) != -1) {
hit = true;
}
}
if (hit) {
possibles[outIndex] = [thisName, this.getEntityId(this.elementList[inIndex]), this.geticon(this.elementList[inIndex])];
outIndex ++;
}
inIndex ++;
}
//
// reset the cursor to the top
//
this.dropDown.current = -1;
return possibles;
};
TypeAheadControl.prototype.handleKeyUp = function(event) {
var key = event.keyCode;
if (27 == key) {
//
// Escape - clear
//
this.textBox.value = '';
this.handleChange();
} else if (8 == key || 32 == key || (key >= 46 && key < 112) || key > 123) {
//
// Backspace, Space and >=Del to <F1 and > F12
//
this.handleChange();
}
};
TypeAheadControl.prototype.handleKeyDown = function(event) {
var key = event.keyCode;
if (38 == key) {
//
// up arrow
//
this.upSelect();
} else if (40 == key) {
//
// down arrow
//
this.downSelect();
}
};
TypeAheadControl.prototype.hideDrop = function() {
var i = 0;
if (null !== this.ie6hack) {
while (i < this.ie6hack.length) {
this.ie6hack[i].style.visibility = 'visible';
i++;
}
}
this.dropDown.style.visibility = 'hidden';
this.textBox.setAttribute('aria-expanded', 'false');
if (-1 == this.dropDown.current) {
this.doUnselected();
}
};
TypeAheadControl.prototype.showDrop = function() {
var i = 0;
if (null !== this.ie6hack) {
while (i < this.ie6hack.length) {
this.ie6hack[i].style.visibility = 'hidden';
i++;
}
}
this.dropDown.style.visibility = 'visible';
this.dropDown.style.width = this.textBox.offsetWidth +"px";
this.textBox.setAttribute('aria-expanded', 'true');
};
TypeAheadControl.prototype.doSelected = function() {
this.submit.disabled = false;
};
TypeAheadControl.prototype.doUnselected = function() {
this.submit.disabled = true;
this.textBox.setAttribute('aria-activedescendant', '');
};
TypeAheadControl.prototype.handleChange = function() {
var val = this.textBox.value;
var res = this.getPossible(val);
if (0 === val.length ||
0 === res.length ||
(!this.alwaysShow && this.maxResults < res.length)) {
this.hideDrop();
this.doUnselected();
this.results = [];
this.dropDown.current = -1;
} else {
this.results = res;
this.populateDropDown(res);
if (1 == res.length) {
this.select(this.dropDown.childNodes[0]);
this.doSelected();
} else {
this.doUnselected();
}
}
};
//
// A lot of the stuff below comes from
// http://www.webreference.com/programming/javascript/ncz/column2
//
// With thanks to Nicholas C Zakas
//
TypeAheadControl.prototype.populateDropDown = function(list) {
this.dropDown.innerHTML = '';
var i = 0;
var li;
var img;
var str;
while (i < list.length) {
li = document.createElement('li');
li.id='IdPSelectOption' + i;
str = list[i][0];
if (null !== list[i][2]) {
img = document.createElement('img');
img.src = list[i][2];
img.width = 16;
img.height = 16;
img.alt = '';
li.appendChild(img);
//
// trim string back further in this case
//
if (str.length > this.maxchars - 2) {
str = str.substring(0, this.maxchars - 2);
}
str = ' ' + str;
} else {
if (str.length > this.maxchars) {
str = str.substring(0, this.maxchars);
}
}
li.appendChild(document.createTextNode(str));
li.setAttribute('role', 'option');
this.dropDown.appendChild(li);
i++;
}
var off = this.getXY();
this.dropDown.style.left = off[0] + 'px';
this.dropDown.style.top = off[1] + 'px';
this.showDrop();
};
TypeAheadControl.prototype.getXY = function() {
var node = this.textBox;
var sumX = 0;
var sumY = node.offsetHeight;
while(node.tagName != 'BODY') {
sumX += node.offsetLeft;
sumY += node.offsetTop;
node = node.offsetParent;
}
//
// And add in the offset for the Body
//
sumX += node.offsetLeft;
sumY += node.offsetTop;
return [sumX, sumY];
};
TypeAheadControl.prototype.select = function(selected) {
var i = 0;
var node;
this.dropDown.current = -1;
this.doUnselected();
while (i < this.dropDown.childNodes.length) {
node = this.dropDown.childNodes[i];
if (node == selected) {
//
// Highlight it
//
node.className = 'IdPSelectCurrent';
node.setAttribute('aria-selected', 'true');
this.textBox.setAttribute('aria-activedescendant', 'IdPSelectOption' + i);
//
// turn on the button
//
this.doSelected();
//
// setup the cursor
//
this.dropDown.current = i;
//
// and the value for the Server
//
this.origin.value = this.results[i][1];
this.origin.textValue = this.results[i][0];
} else {
node.setAttribute('aria-selected', 'false');
node.className = '';
}
i++;
}
this.textBox.focus();
};
TypeAheadControl.prototype.downSelect = function() {
if (this.results.length > 0) {
if (-1 == this.dropDown.current) {
//
// mimic a select()
//
this.dropDown.current = 0;
this.dropDown.childNodes[0].className = 'IdPSelectCurrent';
this.dropDown.childNodes[0].setAttribute('aria-selected', 'true');
this.textBox.setAttribute('aria-activedescendant', 'IdPSelectOption' + 0);
this.doSelected();
this.origin.value = this.results[0][1];
this.origin.textValue = this.results[0][0];
} else if (this.dropDown.current < (this.results.length-1)) {
//
// turn off highlight
//
this.dropDown.childNodes[this.dropDown.current].className = '';
//
// move cursor
//
this.dropDown.current++;
//
// and 'select'
//
this.dropDown.childNodes[this.dropDown.current].className = 'IdPSelectCurrent';
this.dropDown.childNodes[this.dropDown.current].setAttribute('aria-selected', 'true');
this.textBox.setAttribute('aria-activedescendant', 'IdPSelectOption' + this.dropDown.current);
this.doSelected();
this.origin.value = this.results[this.dropDown.current][1];
this.origin.textValue = this.results[this.dropDown.current][0];
}
}
};
TypeAheadControl.prototype.upSelect = function() {
if ((this.results.length > 0) &&
(this.dropDown.current > 0)) {
//
// turn off highlight
//
this.dropDown.childNodes[this.dropDown.current].className = '';
//
// move cursor
//
this.dropDown.current--;
//
// and 'select'
//
this.dropDown.childNodes[this.dropDown.current].className = 'IdPSelectCurrent';
this.dropDown.childNodes[this.dropDown.current].setAttribute('aria-selected', 'true');
this.textBox.setAttribute('aria-activedescendant', 'IdPSelectOption' + this.dropDown.current);
this.doSelected();
this.origin.value = this.results[this.dropDown.current][1];
this.origin.textValue = this.results[this.dropDown.current][0];
}
};
# Basic Apache configuration
<IfModule mod_alias.c>
<Location /shibboleth-ds>
Allow from all
<IfModule mod_shib.c>
AuthType shibboleth
ShibRequestSetting requireSession false
require shibboleth
</IfModule>
</Location>
Alias /shibboleth-ds/idpselect_config.js /etc/shibboleth-ds/idpselect_config.js
Alias /shibboleth-ds/idpselect.js /etc/shibboleth-ds/idpselect.js
Alias /shibboleth-ds/idpselect.css /etc/shibboleth-ds/idpselect.css
Alias /shibboleth-ds/index.html /etc/shibboleth-ds/index.html
Alias /shibboleth-ds/blank.gif /etc/shibboleth-ds/blank.gif
</IfModule>
Name: shibboleth-embedded-ds
Version: 1.2.0
Release: 1
Summary: Client-side federation discovery service for SAML-based SSO
Group: Productivity/Networking/Security
Vendor: Shibboleth Consortium
License: Apache-2.0
URL: http://shibboleth.net/
Source: %{name}-%{version}.tar.gz
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%if "%{_vendor}" == "redhat"
BuildRequires: redhat-rpm-config
%{!?_without_builtinapache:BuildRequires: httpd}
%endif
%if "%{_vendor}" == "suse"
%{!?_without_builtinapache:BuildRequires: apache2}
%endif
%description
The Embedded Discovery Service is a JS/CSS/HTML-based tool for
identity provider selection in conjunction with SAML-based web
single sign-on implementations such as Shibboleth.
%prep
%setup -q
%build
%install
%{__make} install DESTDIR=$RPM_BUILD_ROOT
# Plug the DS into the built-in Apache on a recognized system.
touch rpm.filelist
APACHE_CONFIG="shibboleth-ds.conf"
%{?_without_builtinapache:APACHE_CONFIG="no"}
if [ "$APACHE_CONFIG" != "no" ] ; then
APACHE_CONFD="no"
if [ -d %{_sysconfdir}/httpd/conf.d ] ; then
APACHE_CONFD="%{_sysconfdir}/httpd/conf.d"
fi
if [ -d %{_sysconfdir}/apache2/conf.d ] ; then
APACHE_CONFD="%{_sysconfdir}/apache2/conf.d"
fi
if [ "$APACHE_CONFD" != "no" ] ; then
%{__mkdir} -p $RPM_BUILD_ROOT$APACHE_CONFD
%{__cp} -p $RPM_BUILD_ROOT%{_sysconfdir}/shibboleth-ds/$APACHE_CONFIG $RPM_BUILD_ROOT$APACHE_CONFD/$APACHE_CONFIG
echo "%config(noreplace) $APACHE_CONFD/$APACHE_CONFIG" > rpm.filelist
fi
fi
%clean
[ "$RPM_BUILD_ROOT" != "/" ] && %{__rm} -rf $RPM_BUILD_ROOT
%post
%if "%{_vendor}" == "redhat"
# On upgrade, restart components if they're already running.
if [ "$1" -gt "1" ] ; then
%{!?_without_builtinapache:/sbin/service httpd status 1>/dev/null && /sbin/service httpd restart 1>/dev/null}
exit 0
fi
%endif
%preun
%if "%{_vendor}" == "redhat"
if [ "$1" = 0 ] ; then
%{!?_without_builtinapache:/sbin/service httpd status 1>/dev/null && /sbin/service httpd restart 1>/dev/null}
fi
%endif
%if "%{_vendor}" == "suse"
if [ "$1" = 0 ] ; then
%{!?_without_builtinapache:/sbin/service apache2 status 1>/dev/null && /sbin/service apache2 restart 1>/dev/null}
fi
%endif
exit 0
%postun
%if "%{_vendor}" == "suse"
cd /
%{!?_without_builtinapache:%restart_on_update apache2}
%endif
%files -f rpm.filelist
%defattr(-,root,root,-)
%dir %{_sysconfdir}/shibboleth-ds
%{_sysconfdir}/shibboleth-ds/*.txt
%{_sysconfdir}/shibboleth-ds/*.gif
%config(noreplace) %{_sysconfdir}/shibboleth-ds/index.html
%config(noreplace) %{_sysconfdir}/shibboleth-ds/idpselect.css
%config(noreplace) %{_sysconfdir}/shibboleth-ds/idpselect_config.js
%config %{_sysconfdir}/shibboleth-ds/idpselect.js
%config %{_sysconfdir}/shibboleth-ds/shibboleth-ds.conf
%changelog
* Mon Jun 6 2016 Scott Cantor <cantor.2@osu.edu> - 1.2.0-1
- Update version
- Fix license name
* Wed Apr 29 2015 Scott Cantor <cantor.2@osu.edu> - 1.1.0-1
- Update version
- Stop marking text files as configs
- Add gif to package
* Mon Apr 11 2011 Scott Cantor <cantor.2@osu.edu> - 1.0-1
- First version.
[program:apache2]
command=/usr/sbin/apache2ctl -DFOREGROUND
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=3
[program:gracedb]
command=/usr/local/bin/gunicorn config.wsgi:application --limit-request-field_size 16384 --forwarder-headers 'SCRIPT_NAME,PATH_INFO,REMOTE_USER,ISMEMBEROF,SSL_CLIENT_S_DN,SSL_CLIENT_I_DN,X_FORWARDED_TLS_CLIENT_CERT,X_FORWARDED_TLS_CLIENT_CERT_INFOS' --reload --config /app/gracedb_project/config/gunicorn_config.py --error-logfile='-' --access-logfile='-'
directory=/app/gracedb_project
user=gracedb
group=www-data
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=2
autorestart=unexpected
[program:aws_xray]
autostart=%(ENV_ENABLE_AWS_XRAY)s
command=/usr/bin/xray -f /var/log/xray/xray.log -l info
user=xray
group=xray
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=2
autorestart=true
startretries=100
[program:igwn_alert_overseer]
autostart=%(ENV_ENABLE_IGWN_OVERSEER)s
command=igwn_alert_overseer -a %(ENV_IGWN_ALERT_USER)s -b %(ENV_IGWN_ALERT_PASSWORD)s
-s %(ENV_IGWN_ALERT_SERVER)s -p %(ENV_IGWN_ALERT_OVERSEER_PORT)s
-g %(ENV_IGWN_ALERT_GROUP)s
-l - -e - -q - -c -f -i %(ENV_IGWN_ALERT_FLUSH_INTERVAL)s
user=gracedb
group=www-data
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=2
autorestart=true
startretries=100
[program:redis_server]
autostart=%(ENV_DJANGO_ENABLE_LOCAL_REDIS)s
command=/usr/bin/redis-server /etc/redis/redis.conf --daemonize no
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=3
autorestart=true
startretries=100
[program:redis_qcluster]
autostart=%(ENV_DJANGO_ENABLE_REDIS_QUEUE)s
command=/usr/bin/python3 /app/gracedb_project/manage.py qcluster --settings %(ENV_DJANGO_SETTINGS_MODULE)s
user=gracedb
group=www-data
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=2
autorestart=true
startretries=100
[program:shibd]
autostart=%(ENV_ENABLE_SHIBD)s
command=/usr/sbin/shibd -F
user=_shibd
group=_shibd
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
priority=2