7033 lines
1.0 MiB
7033 lines
1.0 MiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="generator" content="Asciidoctor 1.5.6.1">
|
|
<meta name="author" content="John Dennis">
|
|
<title>mod_auth_mellon User Guide</title>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
|
|
<style>
|
|
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
|
|
/* Remove comment around @import statement below when using as a custom stylesheet */
|
|
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
|
|
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
|
|
audio,canvas,video{display:inline-block}
|
|
audio:not([controls]){display:none;height:0}
|
|
[hidden],template{display:none}
|
|
script{display:none!important}
|
|
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
|
|
a{background:transparent}
|
|
a:focus{outline:thin dotted}
|
|
a:active,a:hover{outline:0}
|
|
h1{font-size:2em;margin:.67em 0}
|
|
abbr[title]{border-bottom:1px dotted}
|
|
b,strong{font-weight:bold}
|
|
dfn{font-style:italic}
|
|
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
|
|
mark{background:#ff0;color:#000}
|
|
code,kbd,pre,samp{font-family:monospace;font-size:1em}
|
|
pre{white-space:pre-wrap}
|
|
q{quotes:"\201C" "\201D" "\2018" "\2019"}
|
|
small{font-size:80%}
|
|
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
|
sup{top:-.5em}
|
|
sub{bottom:-.25em}
|
|
img{border:0}
|
|
svg:not(:root){overflow:hidden}
|
|
figure{margin:0}
|
|
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
|
|
legend{border:0;padding:0}
|
|
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
|
|
button,input{line-height:normal}
|
|
button,select{text-transform:none}
|
|
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
|
|
button[disabled],html input[disabled]{cursor:default}
|
|
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
|
|
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
|
|
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
|
|
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
|
|
textarea{overflow:auto;vertical-align:top}
|
|
table{border-collapse:collapse;border-spacing:0}
|
|
*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
|
|
html,body{font-size:100%}
|
|
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
|
|
a:hover{cursor:pointer}
|
|
img,object,embed{max-width:100%;height:auto}
|
|
object,embed{height:100%}
|
|
img{-ms-interpolation-mode:bicubic}
|
|
.left{float:left!important}
|
|
.right{float:right!important}
|
|
.text-left{text-align:left!important}
|
|
.text-right{text-align:right!important}
|
|
.text-center{text-align:center!important}
|
|
.text-justify{text-align:justify!important}
|
|
.hide{display:none}
|
|
img,object,svg{display:inline-block;vertical-align:middle}
|
|
textarea{height:auto;min-height:50px}
|
|
select{width:100%}
|
|
.center{margin-left:auto;margin-right:auto}
|
|
.spread{width:100%}
|
|
p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
|
|
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
|
|
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
|
|
a{color:#2156a5;text-decoration:underline;line-height:inherit}
|
|
a:hover,a:focus{color:#1d4b8f}
|
|
a img{border:none}
|
|
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
|
|
p aside{font-size:.875em;line-height:1.35;font-style:italic}
|
|
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
|
|
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
|
|
h1{font-size:2.125em}
|
|
h2{font-size:1.6875em}
|
|
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
|
|
h4,h5{font-size:1.125em}
|
|
h6{font-size:1em}
|
|
hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
|
|
em,i{font-style:italic;line-height:inherit}
|
|
strong,b{font-weight:bold;line-height:inherit}
|
|
small{font-size:60%;line-height:inherit}
|
|
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
|
|
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
|
|
ul,ol{margin-left:1.5em}
|
|
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
|
|
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
|
|
ul.square{list-style-type:square}
|
|
ul.circle{list-style-type:circle}
|
|
ul.disc{list-style-type:disc}
|
|
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
|
|
dl dt{margin-bottom:.3125em;font-weight:bold}
|
|
dl dd{margin-bottom:1.25em}
|
|
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
|
|
abbr{text-transform:none}
|
|
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
|
|
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
|
|
blockquote cite:before{content:"\2014 \0020"}
|
|
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
|
|
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
|
|
@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
|
|
h1{font-size:2.75em}
|
|
h2{font-size:2.3125em}
|
|
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
|
|
h4{font-size:1.4375em}}
|
|
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
|
|
table thead,table tfoot{background:#f7f8f7;font-weight:bold}
|
|
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
|
|
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
|
|
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
|
|
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
|
|
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
|
|
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
|
|
.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
|
|
.clearfix:after,.float-group:after{clear:both}
|
|
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
|
|
*:not(pre)>code.nobreak{word-wrap:normal}
|
|
*:not(pre)>code.nowrap{white-space:nowrap}
|
|
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
|
|
em em{font-style:normal}
|
|
strong strong{font-weight:400}
|
|
.keyseq{color:rgba(51,51,51,.8)}
|
|
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
|
|
.keyseq kbd:first-child{margin-left:0}
|
|
.keyseq kbd:last-child{margin-right:0}
|
|
.menuseq,.menuref{color:#000}
|
|
.menuseq b:not(.caret),.menuref{font-weight:inherit}
|
|
.menuseq{word-spacing:-.02em}
|
|
.menuseq b.caret{font-size:1.25em;line-height:.8}
|
|
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
|
|
b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
|
|
b.button:before{content:"[";padding:0 3px 0 2px}
|
|
b.button:after{content:"]";padding:0 2px 0 3px}
|
|
p a>code:hover{color:rgba(0,0,0,.9)}
|
|
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
|
|
#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
|
|
#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
|
|
#content{margin-top:1.25em}
|
|
#content:before{content:none}
|
|
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
|
|
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
|
|
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
|
|
#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
|
|
#header .details span:first-child{margin-left:-.125em}
|
|
#header .details span.email a{color:rgba(0,0,0,.85)}
|
|
#header .details br{display:none}
|
|
#header .details br+span:before{content:"\00a0\2013\00a0"}
|
|
#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
|
|
#header .details br+span#revremark:before{content:"\00a0|\00a0"}
|
|
#header #revnumber{text-transform:capitalize}
|
|
#header #revnumber:after{content:"\00a0"}
|
|
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
|
|
#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
|
|
#toc>ul{margin-left:.125em}
|
|
#toc ul.sectlevel0>li>a{font-style:italic}
|
|
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
|
|
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
|
|
#toc li{line-height:1.3334;margin-top:.3334em}
|
|
#toc a{text-decoration:none}
|
|
#toc a:active{text-decoration:underline}
|
|
#toctitle{color:#7a2518;font-size:1.2em}
|
|
@media only screen and (min-width:768px){#toctitle{font-size:1.375em}
|
|
body.toc2{padding-left:15em;padding-right:0}
|
|
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
|
|
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
|
|
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
|
|
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
|
|
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
|
|
body.toc2.toc-right{padding-left:0;padding-right:15em}
|
|
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
|
|
@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
|
|
#toc.toc2{width:20em}
|
|
#toc.toc2 #toctitle{font-size:1.375em}
|
|
#toc.toc2>ul{font-size:.95em}
|
|
#toc.toc2 ul ul{padding-left:1.25em}
|
|
body.toc2.toc-right{padding-left:0;padding-right:20em}}
|
|
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
|
#content #toc>:first-child{margin-top:0}
|
|
#content #toc>:last-child{margin-bottom:0}
|
|
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
|
|
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
|
|
.sect1{padding-bottom:.625em}
|
|
@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}
|
|
.sect1+.sect1{border-top:1px solid #efefed}
|
|
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
|
|
#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
|
|
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
|
|
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
|
|
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
|
|
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
|
|
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
|
|
table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
|
|
.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
|
|
table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
|
|
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
|
|
.admonitionblock>table td.icon{text-align:center;width:80px}
|
|
.admonitionblock>table td.icon img{max-width:initial}
|
|
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
|
|
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
|
|
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
|
|
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
|
|
.exampleblock>.content>:first-child{margin-top:0}
|
|
.exampleblock>.content>:last-child{margin-bottom:0}
|
|
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
|
.sidebarblock>:first-child{margin-top:0}
|
|
.sidebarblock>:last-child{margin-bottom:0}
|
|
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
|
|
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
|
|
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
|
|
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
|
|
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
|
|
.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
|
|
@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
|
|
@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
|
|
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
|
|
.listingblock pre.highlightjs{padding:0}
|
|
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
|
|
.listingblock pre.prettyprint{border-width:0}
|
|
.listingblock>.content{position:relative}
|
|
.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
|
|
.listingblock:hover code[data-lang]:before{display:block}
|
|
.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
|
|
.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
|
|
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
|
|
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
|
|
table.pyhltable td.code{padding-left:.75em;padding-right:0}
|
|
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
|
|
pre.pygments .lineno{display:inline-block;margin-right:.25em}
|
|
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
|
|
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
|
|
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
|
|
.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
|
|
.quoteblock blockquote{margin:0;padding:0;border:0}
|
|
.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
|
|
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
|
|
.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
|
|
.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
|
|
.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
|
|
.quoteblock .quoteblock blockquote:before{display:none}
|
|
.verseblock{margin:0 1em 1.25em 1em}
|
|
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
|
|
.verseblock pre strong{font-weight:400}
|
|
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
|
|
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
|
|
.quoteblock .attribution br,.verseblock .attribution br{display:none}
|
|
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
|
|
.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
|
|
.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
|
|
.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
|
|
table.tableblock{max-width:100%;border-collapse:separate}
|
|
table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
|
|
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
|
|
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
|
|
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
|
|
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
|
|
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px 0}
|
|
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0 0}
|
|
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
|
|
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
|
|
table.frame-all{border-width:1px}
|
|
table.frame-sides{border-width:0 1px}
|
|
table.frame-topbot{border-width:1px 0}
|
|
th.halign-left,td.halign-left{text-align:left}
|
|
th.halign-right,td.halign-right{text-align:right}
|
|
th.halign-center,td.halign-center{text-align:center}
|
|
th.valign-top,td.valign-top{vertical-align:top}
|
|
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
|
|
th.valign-middle,td.valign-middle{vertical-align:middle}
|
|
table thead th,table tfoot th{font-weight:bold}
|
|
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
|
|
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
|
|
p.tableblock>code:only-child{background:none;padding:0}
|
|
p.tableblock{font-size:1em}
|
|
td>div.verse{white-space:pre}
|
|
ol{margin-left:1.75em}
|
|
ul li ol{margin-left:1.5em}
|
|
dl dd{margin-left:1.125em}
|
|
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
|
|
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
|
|
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
|
|
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
|
|
ul.unstyled,ol.unstyled{margin-left:0}
|
|
ul.checklist{margin-left:.625em}
|
|
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
|
|
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
|
|
ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
|
|
ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
|
|
ul.inline>li>*{display:block}
|
|
.unstyled dl dt{font-weight:400;font-style:normal}
|
|
ol.arabic{list-style-type:decimal}
|
|
ol.decimal{list-style-type:decimal-leading-zero}
|
|
ol.loweralpha{list-style-type:lower-alpha}
|
|
ol.upperalpha{list-style-type:upper-alpha}
|
|
ol.lowerroman{list-style-type:lower-roman}
|
|
ol.upperroman{list-style-type:upper-roman}
|
|
ol.lowergreek{list-style-type:lower-greek}
|
|
.hdlist>table,.colist>table{border:0;background:none}
|
|
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
|
|
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
|
|
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
|
|
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
|
|
.colist>table tr>td:first-of-type{padding:.4em .75em 0 .75em;line-height:1;vertical-align:top}
|
|
.colist>table tr>td:first-of-type img{max-width:initial}
|
|
.colist>table tr>td:last-of-type{padding:.25em 0}
|
|
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
|
|
.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
|
|
.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
|
|
.imageblock>.title{margin-bottom:0}
|
|
.imageblock.thumb,.imageblock.th{border-width:6px}
|
|
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
|
|
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
|
|
.image.left{margin-right:.625em}
|
|
.image.right{margin-left:.625em}
|
|
a.image{text-decoration:none;display:inline-block}
|
|
a.image object{pointer-events:none}
|
|
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
|
|
sup.footnote a,sup.footnoteref a{text-decoration:none}
|
|
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
|
|
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
|
|
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
|
|
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:.2em}
|
|
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
|
|
#footnotes .footnote:last-of-type{margin-bottom:0}
|
|
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
|
|
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
|
|
.gist .file-data>table td.line-data{width:99%}
|
|
div.unbreakable{page-break-inside:avoid}
|
|
.big{font-size:larger}
|
|
.small{font-size:smaller}
|
|
.underline{text-decoration:underline}
|
|
.overline{text-decoration:overline}
|
|
.line-through{text-decoration:line-through}
|
|
.aqua{color:#00bfbf}
|
|
.aqua-background{background-color:#00fafa}
|
|
.black{color:#000}
|
|
.black-background{background-color:#000}
|
|
.blue{color:#0000bf}
|
|
.blue-background{background-color:#0000fa}
|
|
.fuchsia{color:#bf00bf}
|
|
.fuchsia-background{background-color:#fa00fa}
|
|
.gray{color:#606060}
|
|
.gray-background{background-color:#7d7d7d}
|
|
.green{color:#006000}
|
|
.green-background{background-color:#007d00}
|
|
.lime{color:#00bf00}
|
|
.lime-background{background-color:#00fa00}
|
|
.maroon{color:#600000}
|
|
.maroon-background{background-color:#7d0000}
|
|
.navy{color:#000060}
|
|
.navy-background{background-color:#00007d}
|
|
.olive{color:#606000}
|
|
.olive-background{background-color:#7d7d00}
|
|
.purple{color:#600060}
|
|
.purple-background{background-color:#7d007d}
|
|
.red{color:#bf0000}
|
|
.red-background{background-color:#fa0000}
|
|
.silver{color:#909090}
|
|
.silver-background{background-color:#bcbcbc}
|
|
.teal{color:#006060}
|
|
.teal-background{background-color:#007d7d}
|
|
.white{color:#bfbfbf}
|
|
.white-background{background-color:#fafafa}
|
|
.yellow{color:#bfbf00}
|
|
.yellow-background{background-color:#fafa00}
|
|
span.icon>.fa{cursor:default}
|
|
a span.icon>.fa{cursor:inherit}
|
|
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
|
|
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
|
|
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
|
|
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
|
|
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
|
|
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
|
|
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
|
|
.conum[data-value] *{color:#fff!important}
|
|
.conum[data-value]+b{display:none}
|
|
.conum[data-value]:after{content:attr(data-value)}
|
|
pre .conum[data-value]{position:relative;top:-.125em}
|
|
b.conum *{color:inherit!important}
|
|
.conum:not([data-value]):empty{display:none}
|
|
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
|
|
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
|
|
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
|
|
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
|
|
p{margin-bottom:1.25rem}
|
|
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
|
|
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
|
|
.print-only{display:none!important}
|
|
@media print{@page{margin:1.25cm .75cm}
|
|
*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
|
|
a{color:inherit!important;text-decoration:underline!important}
|
|
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
|
|
a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
|
|
abbr[title]:after{content:" (" attr(title) ")"}
|
|
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
|
|
thead{display:table-header-group}
|
|
svg{max-width:100%}
|
|
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
|
|
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
|
|
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
|
|
#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
|
|
.sect1{padding-bottom:0!important}
|
|
.sect1+.sect1{border:0!important}
|
|
#header>h1:first-child{margin-top:1.25rem}
|
|
body.book #header{text-align:center}
|
|
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0}
|
|
body.book #header .details{border:0!important;display:block;padding:0!important}
|
|
body.book #header .details span:first-child{margin-left:0!important}
|
|
body.book #header .details br{display:block}
|
|
body.book #header .details br+span:before{content:none!important}
|
|
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
|
|
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
|
|
.listingblock code[data-lang]:before{display:block}
|
|
#footer{background:none!important;padding:0 .9375em}
|
|
#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em}
|
|
.hide-on-print{display:none!important}
|
|
.print-only{display:block!important}
|
|
.hide-for-print{display:none!important}
|
|
.show-for-print{display:inherit!important}}
|
|
</style>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
|
|
</head>
|
|
<body class="article toc2 toc-left">
|
|
<div id="header">
|
|
<h1>mod_auth_mellon User Guide</h1>
|
|
<div class="details">
|
|
<span id="author" class="author">John Dennis</span><br>
|
|
<span id="email" class="email"><a href="mailto:jdennis@redhat.com">jdennis@redhat.com</a></span><br>
|
|
<span id="revnumber">version 1.3,</span>
|
|
<span id="revdate">2018-02-22</span>
|
|
</div>
|
|
<div id="toc" class="toc2">
|
|
<div id="toctitle">Table of Contents</div>
|
|
<ul class="sectlevel1">
|
|
<li><a href="#_colophon">1. Colophon</a></li>
|
|
<li><a href="#_document_conventions">2. Document Conventions</a></li>
|
|
<li><a href="#_introduction">3. Introduction</a></li>
|
|
<li><a href="#_saml_overview">4. SAML Overview</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#saml_roles">4.1. SAML Roles</a></li>
|
|
<li><a href="#saml_profiles">4.2. SAML Profiles</a></li>
|
|
<li><a href="#saml_bindings">4.3. SAML Bindings</a></li>
|
|
<li><a href="#_saml_messages">4.4. SAML Messages</a></li>
|
|
<li><a href="#web_sso_flow">4.5. SAML Web-SSO flow</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#saml_sessions">4.5.1. Sessions</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#http_post">4.6. HTTP Post and Self-Posting</a></li>
|
|
<li><a href="#entityID">4.7. entityID</a></li>
|
|
<li><a href="#name_id">4.8. Username, userid, SAML NameID</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#_userid_vs_identity_or_why_userid_is_so_last_millennium">4.8.1. Userid vs. Identity (or why userid is so last millennium)</a></li>
|
|
<li><a href="#saml_nameid">4.8.2. How SAML identifies a subject</a></li>
|
|
<li><a href="#nameid_interpretation">4.8.3. Burden of interpreting NameID falls to the relying party</a></li>
|
|
<li><a href="#_how_mellon_handles_the_nameid">4.8.4. How Mellon handles the NameID</a></li>
|
|
<li><a href="#specify_mellon_nameid">4.8.5. How do you specify the NameID format in SAML?</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#authentication_request">4.9. <AuthnRequest> Example</a></li>
|
|
<li><a href="#assertion_response">4.10. <Assertion> Example</a></li>
|
|
<li><a href="#endpoints">4.11. SAML Endpoints</a></li>
|
|
<li><a href="#relaystate">4.12. Relay State (How you return to the original URL)</a></li>
|
|
<li><a href="#metadata">4.13. The Role of Metadata</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#metadata_keys">4.13.1. Certs and Keys Inside Metadata</a></li>
|
|
<li><a href="#sp_metadata">4.13.2. Service Provider Metadata</a></li>
|
|
<li><a href="#idp_metadata">4.13.3. Identity Provider Metadata</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_installing_configuring_mellon">5. Installing & Configuring Mellon</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_installing_mellon">5.1. Installing Mellon</a></li>
|
|
<li><a href="#mellon_config">5.2. Mellon Configuration</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#load_mod_auth_mellon">5.2.1. Load mod_auth_mellon</a></li>
|
|
<li><a href="#mellon_config_files">5.2.2. Mellon Configuration Files</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_mellon_configuration_directives">5.3. Mellon Configuration Directives</a></li>
|
|
<li><a href="#mellon_config_file">5.4. Mellon Configuration File</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#load_sp_metadata_into_idp">5.4.1. Load Your SP metadata into the IdP</a></li>
|
|
<li><a href="#obtain_idp_metadata">5.4.2. Obtaining IdP Metadata</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mellon_modes">5.5. Mellon Modes</a></li>
|
|
<li><a href="#metadata_creation">5.6. How is Mellon metadata created?</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#using_mellon_create_metadata_sh">5.6.1. Using <code>mellon_create_metadata.sh</code></a></li>
|
|
<li><a href="#using_mellon_to_create_metadata">5.6.2. Using Mellon to generate its own metadata</a></li>
|
|
<li><a href="#_where_do_the_keys_and_certs_come_from">5.6.3. Where do the keys and certs come from?</a></li>
|
|
<li><a href="#sign_metadata">5.6.4. Signing metadata</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mellon_endpoint_path">5.7. MellonEndpointPath</a></li>
|
|
<li><a href="#mellon_endpoints">5.8. Mellon Endpoints</a></li>
|
|
<li><a href="#mellon_session">5.9. Mellon Session</a></li>
|
|
<li><a href="#mellon_cookie">5.10. Mellon Cookie</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_working_with_saml_attributes_and_exporting_values_to_web_apps">6. Working with SAML attributes and exporting values to web apps</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#multiple_attribute_values">6.1. Handling multiple attribute values</a></li>
|
|
<li><a href="#map_assertion_attr_name">6.2. Map assertion attribute name to different Apache environment variable name</a></li>
|
|
<li><a href="#assertion_constraints">6.3. Using Mellon to apply constraints</a></li>
|
|
<li><a href="#set_remote_user">6.4. How to set REMOTE_USER</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#deployment_considerations">7. Deployment Considerations</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#apache_servername">7.1. Apache Servername</a></li>
|
|
<li><a href="#load_balancer">7.2. Load Balancer Issues</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#_server_name">7.2.1. Server Name</a></li>
|
|
<li><a href="#load_balancer_persistence">7.2.2. Load balancer proxy persistence</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#forwarded_http_headers">7.3. Forwarded HTTP Headers</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#error_response">8. When a SAML party responds with an error</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_top_level_status_codes">8.1. Top-level status codes</a></li>
|
|
<li><a href="#_second_level_status_codes">8.2. Second-level status codes</a></li>
|
|
<li><a href="#_status_code_examples">8.3. Status code examples</a></li>
|
|
<li><a href="#find_status_code">8.4. Finding the <code>StatusCode</code></a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#gather_runtime_info">9. Gathering run-time information</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_apache_log_files">9.1. Apache log files</a></li>
|
|
<li><a href="#trace_saml_flow">9.2. Trace SAML flow</a></li>
|
|
<li><a href="#inspect_saml_messages">9.3. Inspect SAML messages</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#saml_tracer">9.3.1. Firefox SAML Tracer</a></li>
|
|
<li><a href="#_chrome_saml_chrome_panel">9.3.2. Chrome, SAML Chrome Panel</a></li>
|
|
<li><a href="#encrypted_response">9.3.3. If the IdP response is encrypted</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#inspect_mellon_env">9.4. Inspecting Mellon environment variables</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#_python_wsgi_environment_dump">9.4.1. Python WSGI Environment Dump</a></li>
|
|
<li><a href="#_php_environment_dump">9.4.2. PHP Environment Dump</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mellon_diagnostics">9.5. Mellon Diagnostics</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#using_mellon_diagnostics">9.5.1. Using Mellon Diagnostics</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_potential_problems">10. Potential Problems</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_it_s_the_metadata">10.1. It’s the metadata</a></li>
|
|
<li><a href="#_behavior_does_not_change_after_modifying_any_saml_file">10.2. Behavior does not change after modifying any SAML file</a></li>
|
|
<li><a href="#_are_the_mellon_configuration_directives_syntactically_correct">10.3. Are the Mellon configuration directives syntactically correct?</a></li>
|
|
<li><a href="#_no_authnrequest_sent_to_idp">10.4. No AuthnRequest sent to IdP</a></li>
|
|
<li><a href="#incorrect_mellon_endpoint_path">10.5. Incorrect MellonEndpointPath</a></li>
|
|
<li><a href="#invalid_destination">10.6. HTTP_BAD_REQUEST - Invalid Destination on Response</a></li>
|
|
<li><a href="#_mellon_metadata_out_of_sync_with_mellon_configuration">10.7. Mellon metadata out of sync with Mellon configuration</a></li>
|
|
<li><a href="#_microsoft_adfs_issues">10.8. Microsoft ADFS issues</a>
|
|
<ul class="sectlevel3">
|
|
<li><a href="#adfs_sig_alg">10.8.1. ADFS Signature Algorithm</a></li>
|
|
<li><a href="#adfs_nameid_policy">10.8.2. ADFS NameIDPolicy</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_time_sync">10.9. Time Sync</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#_glossary">11. Glossary</a></li>
|
|
<li><a href="#_appendix">Appendix A: Appendix</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#authentication_request_wire">A.1. Example On-The-Wire AuthnRequest</a></li>
|
|
<li><a href="#assertion_response_wire">A.2. Example On-the-Wire <Assertion> response</a></li>
|
|
<li><a href="#mellon_diagnostics_example">A.3. Example Mellon Diagnostics</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="content">
|
|
<div class="sect1">
|
|
<h2 id="_colophon">1. Colophon</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Author: John Dennis <a href="mailto:jdennis@redhat.com">jdennis@redhat.com</a></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Version: 1.3</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Date: 2018-02-22</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_document_conventions">2. Document Conventions</h2>
|
|
<div class="sectionbody">
|
|
<div class="sidebarblock">
|
|
<div class="content">
|
|
<div class="title">Example Data used in this document</div>
|
|
<div class="paragraph">
|
|
<p>This document contains many examples of SAML data. For consistency we
|
|
will use the following:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>The SP is hosted on the node <code>mellon.example.com</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>The SP <code>MellonEndpointPath</code> is <code>/mellon</code></p>
|
|
</li>
|
|
<li>
|
|
<p>The SP <code>entityID</code> is <code><a href="https://mellon.example.com/mellon/metadata" class="bare">https://mellon.example.com/mellon/metadata</a></code></p>
|
|
</li>
|
|
<li>
|
|
<p>Mellon is protecting the URL location <code>/private</code> and everything
|
|
under it.</p>
|
|
</li>
|
|
<li>
|
|
<p>The protected resource is <code>/private/info.html</code> and hence the URL of
|
|
the protected resource is <code><a href="https://mellon.example.com/private/info.html" class="bare">https://mellon.example.com/private/info.html</a></code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>The IdP is hosted on the node <code>rhsso.example.com</code></p>
|
|
</li>
|
|
<li>
|
|
<p>The IdP <code>entityID</code> is <code><a href="https://rhsso.example.com:8443/auth/realms/test" class="bare">https://rhsso.example.com:8443/auth/realms/test</a></code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_introduction">3. Introduction</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>mod_auth_mellon is an Apache (httpd) authentication module
|
|
providing authentication and authorization services via SAML. Mellon
|
|
plays the role of a <em>Service Provider</em> (SP) in SAML.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_saml_overview">4. SAML Overview</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>SAML (<em>Security Assertion Markup Language</em>) is a framework for exchanging
|
|
security information between providers. The nonprofit
|
|
<a href="https://www.oasis-open.org/">OASIS</a> consortium is responsible for
|
|
defining and publishing the various SAML specifications. OASIS is an
|
|
acronym for <em>Organization for the Advancement of Structured
|
|
Information Standards</em>. All SAML specifications and errata can be
|
|
found at this location:</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><a href="https://docs.oasis-open.org/security/saml/v2.0/" class="bare">https://docs.oasis-open.org/security/saml/v2.0/</a></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The SAML technical committee has published the
|
|
<a href="https://www.oasis-open.org/committees/download.php/27819/sstc-saml-tech-overview-2.0-cd-02.pdf">Security
|
|
Assertion Markup Language (SAML) V2.0 Technical Overview</a>. This is an
|
|
excellent high-level overview of SAML and worth reading to familiarize
|
|
yourself with general SAML operation and terminology.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML is a large complex standard that currently comprises 10 individual
|
|
specifications whose total content is hundreds of pages of printed
|
|
material. SAML is much too large to cover in this overview. Instead we
|
|
will focus on the most common use of SAML, Web Single Sign-On
|
|
(Web-SSO). This is the target focus of mod_auth_mellon, although
|
|
Mellon does support other profiles as well.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML organizes itself into <a href="#saml_profiles">Profiles</a> and
|
|
<a href="#saml_binding">Bindings</a>. A cursory overview of these two concepts
|
|
will help you understand SAML better and is especially important if
|
|
you have to refer to any SAML specifications.</p>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="saml_roles">4.1. SAML Roles</h3>
|
|
<div class="paragraph">
|
|
<p>Participants in SAML play different roles. An entity may be capable of
|
|
playing more than one role, however we typically only consider a single role when
|
|
discussing entity behavior. The defined SAML roles are:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Identity Provider (IdP)</p>
|
|
</li>
|
|
<li>
|
|
<p>Service Provider (SP)</p>
|
|
</li>
|
|
<li>
|
|
<p>Affiliation</p>
|
|
</li>
|
|
<li>
|
|
<p>Attribute Authority</p>
|
|
</li>
|
|
<li>
|
|
<p>Attribute Consumer</p>
|
|
</li>
|
|
<li>
|
|
<p>Policy Decision Point</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Of these we are only interested in Service Providers (SP) and Identity
|
|
Providers (IdP). Mellon is a Service Provider because it provides a
|
|
service to clients. Authentication and user information is provided by
|
|
an Identity Provider. The SP relies on the IdP for its authentication
|
|
needs. In SAML literature you will often see the term <em>attesting
|
|
party</em> or <em>asserting party</em>, which in most contexts means an IdP
|
|
because the IdP attests to or asserts certain claims in its role as
|
|
an <em>authority</em>. On the other hand a Service Provider is often referred
|
|
to as a <em>relying party</em> because it <em>relies</em> on the <em>assertions</em>
|
|
provided by an <em>authority</em>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="saml_profiles">4.2. SAML Profiles</h3>
|
|
<div class="paragraph">
|
|
<p>A SAML profile defines how SAML data is conveyed using
|
|
<a href="#saml_bindings">SAML Bindings</a> on a transport to accomplish a specific task. The
|
|
<em>Web Browser SSO Profile</em> is the best known and the one Mellon focuses
|
|
on. Other profiles include <em>Single Logout</em>, <em>Enhanced Client or Proxy
|
|
(ECP)</em>, <em>Identity Provider Discovery</em>, etc.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML profiles are defined in the <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf">Profiles
|
|
for the OASIS Security Assertion Markup Language (SAML) V2.0</a> specification.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="saml_bindings">4.3. SAML Bindings</h3>
|
|
<div class="paragraph">
|
|
<p>SAML bindings define how SAML messages are mapped onto standard
|
|
messaging or communication protocols. The best way to think of a SAML
|
|
binding is as a transport mechanism. A key concept is that a given
|
|
SAML profile may permit the same SAML message to be conveyed using
|
|
variety of SAML bindings. Or by the same token a SAML profile may
|
|
prohibit the use of certain SAML bindings.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML bindings are defined in the
|
|
<a href="https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf">Bindings
|
|
for the OASIS Security Assertion Markup Language (SAML) V2.0</a>
|
|
specification.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_saml_messages">4.4. SAML Messages</h3>
|
|
<div class="paragraph">
|
|
<p>All SAML messages are conveyed as XML documents. A SAML XML message
|
|
may be transported in a variety of mechanisms known as a
|
|
<a href="#saml_bindings">SAML binding</a>. Examples of SAML bindings include:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>query parameters of an HTTP URL.</p>
|
|
</li>
|
|
<li>
|
|
<p>parameters of an HTML form.</p>
|
|
</li>
|
|
<li>
|
|
<p>wrapped in a SOAP message.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The exact way a SAML interchange operates and the SAML bindings which
|
|
are utilized in each step define what is called a SAML
|
|
<a href="#saml_profiles">SAML profile</a>. For example web-sso is defined by the
|
|
<em>Web Browser SSO Profile</em>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML data, and its XML schema are defined in the <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">Assertions and Protocols for the OASIS
|
|
Security Assertion Markup Language
|
|
(SAML) V2.0</a> <em>core</em> specification.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="web_sso_flow">4.5. SAML Web-SSO flow</h3>
|
|
<div class="paragraph">
|
|
<p>The <em>Web Browser SSO Profile</em> is the best known <a href="#saml_profiles">SAML
|
|
profile</a> and the one Mellon focuses on. Your ability to configure
|
|
Mellon and diagnose Mellon deployment issues will be greatly enhanced
|
|
if you understand this flow and the two SAML messages conveyed in the
|
|
flow, <em>SAML AuthnRequest</em> and <em>SAML Assertion Response</em>.</p>
|
|
</div>
|
|
<div class="imageblock">
|
|
<div class="content">
|
|
<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNi43NzY1NDZpbiIKICAgaGVpZ2h0PSI1Ljk2ODgxMWluIgogICB2aWV3Qm94PSIwIDAgMTcyLjEyNDI3IDE1MS42MDc4IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc4IgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyK2RldmVsIHVua25vd24iCiAgIHNvZGlwb2RpOmRvY25hbWU9InNhbWwtd2ViLXNzby5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyIj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MkxlbmQiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJtYXJrZXIxMzU0MiIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTM1NDAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNjI1O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpZD0ibWFya2VyMTIxOTQiCiAgICAgICByZWZYPSIwIgogICAgICAgcmVmWT0iMCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MkxlbmQiPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4xLDAsMCwtMS4xLC0xLjEsMCkiCiAgICAgICAgIGQ9Ik0gOC43MTg1ODc4LDQuMDMzNzM1MiAtMi4yMDcyODk1LDAuMDE2MDEzMjYgOC43MTg1ODg0LC00LjAwMTcwNzggYyAtMS43NDU0OTg0LDIuMzcyMDYwOSAtMS43MzU0NDA4LDUuNjE3NDUxOSAtNmUtNyw4LjAzNTQ0MyB6IgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InBhdGgxMjE5MiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjEyMDA4IgogICAgICAgcmVmWD0iMCIKICAgICAgIHJlZlk9IjAiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJwYXRoMTIwMDYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlkPSJtYXJrZXIxMTEyMSIKICAgICAgIHJlZlg9IjAiCiAgICAgICByZWZZPSIwIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCI+CiAgICAgIDxwYXRoCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNjI1O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icGF0aDExMTE5IgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0ibWFya2VyMTA1NjEiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDEwNTU5IgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjEwMzY3IgogICAgICAgcmVmWD0iMCIKICAgICAgIHJlZlk9IjAiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJwYXRoMTAzNjUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MUxzdGFydCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjEwMTgzIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgxMDE4MSIKICAgICAgICAgZD0iTSAwLDAgNSwtNSAtMTIuNSwwIDUsNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjAwMDAwMDAzcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44LDAsMCwwLjgsMTAsMCkiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MUxzdGFydCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjEwMDQ3IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgxMDA0NSIKICAgICAgICAgZD0iTSAwLDAgNSwtNSAtMTIuNSwwIDUsNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjAwMDAwMDAzcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44LDAsMCwwLjgsMTAsMCkiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlkPSJtYXJrZXI5OTI5IgogICAgICAgcmVmWD0iMCIKICAgICAgIHJlZlk9IjAiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIj4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJwYXRoOTkyNyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjk4MTEiCiAgICAgICByZWZYPSIwIgogICAgICAgcmVmWT0iMCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MkxlbmQiPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4xLDAsMCwtMS4xLC0xLjEsMCkiCiAgICAgICAgIGQ9Ik0gOC43MTg1ODc4LDQuMDMzNzM1MiAtMi4yMDcyODk1LDAuMDE2MDEzMjYgOC43MTg1ODg0LC00LjAwMTcwNzggYyAtMS43NDU0OTg0LDIuMzcyMDYwOSAtMS43MzU0NDA4LDUuNjE3NDUxOSAtNmUtNyw4LjAzNTQ0MyB6IgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InBhdGg5ODA5IgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzFMc3RhcnQiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJtYXJrZXI5NjM5IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGg5NjM3IgogICAgICAgICBkPSJNIDAsMCA1LC01IC0xMi41LDAgNSw1IFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMDAwMDAwMDNwdDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgsMCwwLDAuOCwxMCwwKSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cxTHN0YXJ0IgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0iQXJyb3cxTHN0YXJ0IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGg0MzY0IgogICAgICAgICBkPSJNIDAsMCA1LC01IC0xMi41LDAgNSw1IFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMDAwMDAwMDNwdDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgsMCwwLDAuOCwxMCwwKSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjk0NTMiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDk0NTEiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNjI1O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0ibWFya2VyOTM1OSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoOTM1NyIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gOC43MTg1ODc4LDQuMDMzNzM1MiAtMi4yMDcyODk1LDAuMDE2MDEzMjYgOC43MTg1ODg0LC00LjAwMTcwNzggYyAtMS43NDU0OTg0LDIuMzcyMDYwOSAtMS43MzU0NDA4LDUuNjE3NDUxOSAtNmUtNyw4LjAzNTQ0MyB6IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4xLDAsMCwtMS4xLC0xLjEsMCkiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlkPSJtYXJrZXI5MTc2IgogICAgICAgcmVmWD0iMCIKICAgICAgIHJlZlk9IjAiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIj4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJwYXRoOTE3NCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjg5NDgiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDg5NDYiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNjI1O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIDguNzE4NTg3OCw0LjAzMzczNTIgLTIuMjA3Mjg5NSwwLjAxNjAxMzI2IDguNzE4NTg4NCwtNC4wMDE3MDc4IGMgLTEuNzQ1NDk4NCwyLjM3MjA2MDkgLTEuNzM1NDQwOCw1LjYxNzQ1MTkgLTZlLTcsOC4wMzU0NDMgeiIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMSwwLDAsLTEuMSwtMS4xLDApIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzFNZW5kIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0iQXJyb3cxTWVuZCIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoNDM3MyIKICAgICAgICAgZD0iTSAwLDAgNSwtNSAtMTIuNSwwIDUsNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjAwMDAwMDAzcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTAuNCwwLDAsLTAuNCwtNCwwKSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjg1MjEiCiAgICAgICByZWZYPSIwIgogICAgICAgcmVmWT0iMCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MkxlbmQiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4xLDAsMCwtMS4xLC0xLjEsMCkiCiAgICAgICAgIGQ9Ik0gOC43MTg1ODc4LDQuMDMzNzM1MiAtMi4yMDcyODk1LDAuMDE2MDEzMjYgOC43MTg1ODg0LC00LjAwMTcwNzggYyAtMS43NDU0OTg0LDIuMzcyMDYwOSAtMS43MzU0NDA4LDUuNjE3NDUxOSAtNmUtNyw4LjAzNTQ0MyB6IgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InBhdGg4NTE5IgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJBcnJvdzJMZW5kIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0ibWFya2VyODEzMyIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoODEzMSIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MjU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gOC43MTg1ODc4LDQuMDMzNzM1MiAtMi4yMDcyODk1LDAuMDE2MDEzMjYgOC43MTg1ODg0LC00LjAwMTcwNzggYyAtMS43NDU0OTg0LDIuMzcyMDYwOSAtMS43MzU0NDA4LDUuNjE3NDUxOSAtNmUtNyw4LjAzNTQ0MyB6IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4xLDAsMCwtMS4xLC0xLjEsMCkiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L21hcmtlcj4KICAgIDxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MkxlbmQiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJBcnJvdzJMZW5kIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGg0Mzg1IgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9IkFycm93MkxlbmQtNiIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDM4NS0yIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9IkFycm93MkxlbmQtOSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDM4NS0wIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjYyNTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjkxNzYtMiIKICAgICAgIHJlZlg9IjAiCiAgICAgICByZWZZPSIwIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cyTGVuZCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjEsMCwwLC0xLjEsLTEuMSwwKSIKICAgICAgICAgZD0iTSA4LjcxODU4NzgsNC4wMzM3MzUyIC0yLjIwNzI4OTUsMC4wMTYwMTMyNiA4LjcxODU4ODQsLTQuMDAxNzA3OCBjIC0xLjc0NTQ5ODQsMi4zNzIwNjA5IC0xLjczNTQ0MDgsNS42MTc0NTE5IC02ZS03LDguMDM1NDQzIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNjI1O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icGF0aDkxNzQtMSIgLz4KICAgIDwvbWFya2VyPgogICAgPG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iQXJyb3cxTWVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9IkFycm93MU1lbmQtMSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDM3My02IgogICAgICAgICBkPSJNIDAsMCA1LC01IC0xMi41LDAgNSw1IFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMDAwMDAwMDNwdDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMC40LDAsMCwtMC40LC00LDApIiAvPgogICAgPC9tYXJrZXI+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSIwLjk4OTk0OTQ5IgogICAgIGlua3NjYXBlOmN4PSIyODkuMTY5MzgiCiAgICAgaW5rc2NhcGU6Y3k9IjI4My45ODM3MSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0ibW0iCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXJvdGF0aW9uPSIwIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMTAzIgogICAgIGlua3NjYXBlOndpbmRvdy14PSIwIgogICAgIGlua3NjYXBlOndpbmRvdy15PSIyNyIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNuYXAtdGV4dC1iYXNlbGluZT0idHJ1ZSIKICAgICB1bml0cz0iaW4iPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkNDI2NyIKICAgICAgIG9yaWdpbng9Ii0xMjMuMDQyMzYiCiAgICAgICBvcmlnaW55PSItMzIwLjM3MDc5IiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNC40OTAxMjUsLTE2LjE4ODY2NikiPgogICAgPGcKICAgICAgIGlkPSJnODA5NCI+CiAgICAgIDxnCiAgICAgICAgIGlkPSJnNDM0OSI+CiAgICAgICAgPHJlY3QKICAgICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC43MDU5OTk5NztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InJlY3Q0MjY5IgogICAgICAgICAgIHdpZHRoPSIzNi40NTk1ODMiCiAgICAgICAgICAgaGVpZ2h0PSIxNS44NzUiCiAgICAgICAgICAgeD0iMTQuODQzMTI1IgogICAgICAgICAgIHk9IjE2LjU0MTY2NiIgLz4KICAgICAgICA8dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6My45Njg3NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjt0ZXh0LWFsaWduOmNlbnRlcjtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6bWlkZGxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgeD0iMzIuODgwMDk2IgogICAgICAgICAgIHk9IjIxLjgzMzI5NCIKICAgICAgICAgICBpZD0idGV4dDQyNzMiPjx0c3BhbgogICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgIGlkPSJ0c3BhbjQyNzEiCiAgICAgICAgICAgICB4PSIzMi44ODAwOTYiCiAgICAgICAgICAgICB5PSIyMS44MzMyOTQiCiAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCI+QnJvd3NlcjwvdHNwYW4+PC90ZXh0PgogICAgICA8L2c+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDM2MiIKICAgICAgICAgZD0iTSAzMy4wNjgyNTYsMzIuNDE2NjY4IFYgMTY3LjM1NDE3IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjQXJyb3cyTGVuZCkiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgaWQ9Imc4MTE0Ij4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0MzU1Ij4KICAgICAgICA8cmVjdAogICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjcwNTk5OTk3O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBpZD0icmVjdDQyNjktMiIKICAgICAgICAgICB3aWR0aD0iMzYuNDU5NTgzIgogICAgICAgICAgIGhlaWdodD0iMTUuODc1IgogICAgICAgICAgIHg9IjgyLjMxMTg3NCIKICAgICAgICAgICB5PSIxNi41NDE2NjYiIC8+CiAgICAgICAgPHRleHQKICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjMuOTY4NzVweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7dGV4dC1hbGlnbjpjZW50ZXI7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOm1pZGRsZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIHg9IjEwMC4zNDg4NSIKICAgICAgICAgICB5PSIyMS44MzMyOTQiCiAgICAgICAgICAgaWQ9InRleHQ0MjczLTUiPjx0c3BhbgogICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgIGlkPSJ0c3BhbjQyNzEtOCIKICAgICAgICAgICAgIHg9IjEwMC4zNDg4NSIKICAgICAgICAgICAgIHk9IjIxLjgzMzI5NCIKICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4Ij5TZXJ2aWNlIFByb3ZpZGVyPC90c3Bhbj48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICB4PSIxMDAuMzQ4ODUiCiAgICAgICAgICAgICB5PSIyNi43OTQyMzEiCiAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgICAgIGlkPSJ0c3BhbjQzMjUiPihlLmcuIE1lbGxvbik8L3RzcGFuPjwvdGV4dD4KICAgICAgPC9nPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQzNjItOSIKICAgICAgICAgZD0iTSAxMDAuNTM3MDEsMzIuNDE2NjY4IFYgMTY3LjM1NDE3IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjQXJyb3cyTGVuZC02KSIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpZD0iZzgxMjciPgogICAgICA8ZwogICAgICAgICBpZD0iZzQzNjAiPgogICAgICAgIDxyZWN0CiAgICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNzA1OTk5OTc7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJyZWN0NDI2OS02IgogICAgICAgICAgIHdpZHRoPSIzNi41MDE5NDIiCiAgICAgICAgICAgaGVpZ2h0PSIxNS44NzUiCiAgICAgICAgICAgeD0iMTQ5Ljc1OTQ1IgogICAgICAgICAgIHk9IjE2LjU0MTY2NiIgLz4KICAgICAgICA8dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6My45Njg3NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjt0ZXh0LWFsaWduOmNlbnRlcjtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6bWlkZGxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgeD0iMTY3LjgxNzYiCiAgICAgICAgICAgeT0iMjEuODMzMjk0IgogICAgICAgICAgIGlkPSJ0ZXh0NDI3My0yIj48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW40MjcxLTg0IgogICAgICAgICAgICAgeD0iMTY3LjgxNzYiCiAgICAgICAgICAgICB5PSIyMS44MzMyOTQiCiAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCI+SWRlbnRpdHkgUHJvdmlkZXI8L3RzcGFuPjwvdGV4dD4KICAgICAgPC9nPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQzNjItOCIKICAgICAgICAgZD0iTSAxNjguMDA1NzYsMzIuNDE2NjY4IFYgMTY3LjM1NDE3IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjQXJyb3cyTGVuZC05KSIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDwvZz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjQwNTY5NDQzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyLWVuZDp1cmwoI21hcmtlcjgxMzMpIgogICAgICAgZD0ibSAzMi45ODA4NzgsNDYuNTI0NDQ5IDY3LjI0MzEwMiwtMC4wNzAzOSIKICAgICAgIGlkPSJwYXRoODEyOSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgeT0iMzkuNzM0MDU1IgogICAgICAgaWQ9InRleHQ4MTczIj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuODE3MSIKICAgICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgICB5PSIzOS43MzQwNTUiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4Ij48dHNwYW4KICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBCb2xkJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQiCiAgIGlkPSJ0c3Bhbjg5MzAiPjEuPC90c3Bhbj4gVXNlciBhdHRlbXB0cyB0byBhY2Nlc3M8L3RzcGFuPjx0c3BhbgogICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICB4PSI0MS4wMDMzNzYiCiAgICAgICAgIHk9IjQzLjcwMjgwNSIKICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHgiCiAgICAgICAgIGlkPSJ0c3BhbjgxNzUiPnJlc291cmNlIGF0IFNQPC90c3Bhbj48L3RleHQ+CiAgICA8ZwogICAgICAgaWQ9ImcxNDE2NSI+CiAgICAgIDxyZWN0CiAgICAgICAgIHk9IjM3LjIzNTM3MSIKICAgICAgICAgeD0iMTA2Ljg2MjM5IgogICAgICAgICBoZWlnaHQ9IjkuMzAzMTQ1NCIKICAgICAgICAgd2lkdGg9IjUyLjczNjM2NiIKICAgICAgICAgaWQ9InJlY3Q4MTc3IgogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC4xNzYzODg4OTtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDx0ZXh0CiAgICAgICAgIGlkPSJ0ZXh0ODE4MSIKICAgICAgICAgeT0iNDAuOTI0MjEiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHRzcGFuCiAgICAgICAgICAgaWQ9InRzcGFuODE4MyIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgICB5PSI0MC45MjQyMSIKICAgICAgICAgICB4PSIxMDguNDA5NjEiCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSI+SXMgdGhlcmUgYSBzZXNzaW9uIGZvciB0aGlzIHVzZXI/PC90c3Bhbj48dHNwYW4KICAgICAgICAgICBpZD0idHNwYW44MTg3IgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICAgIHk9IjQ0Ljg5Mjk2IgogICAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIj5ObywgdGhlbiBjcmVhdGUgb25lLjwvdHNwYW4+PC90ZXh0PgogICAgPC9nPgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZTozLjk2ODc1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmO3RleHQtYWxpZ246Y2VudGVyO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjptaWRkbGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIHg9IjEzMC44ODI5OCIKICAgICAgIHk9IjQzLjIyMTQxNiIKICAgICAgIGlkPSJ0ZXh0ODE5MSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjgxODkiCiAgICAgICAgIHg9IjEzMC44ODI5OCIKICAgICAgICAgeT0iNDYuNzMyODMiCiAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4Ij48L3RzcGFuPjwvdGV4dD4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjQwNTY5NDQzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyLWVuZDp1cmwoI21hcmtlcjg1MjEpIgogICAgICAgZD0iTSAxMDAuNTQxNjcsNTYuMjI5MTY3IEggMjkuMTA0MTY3IHYgNy45Mzc1IGwgMTM3Ljg3MzUyMywwLjQ3NTMwNiIKICAgICAgIGlkPSJwYXRoODUxMSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiIC8+CiAgICA8dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSIxMDguNDA5NjEiCiAgICAgICB5PSI1NC45MDE0MjQiCiAgICAgICBpZD0idGV4dDgxNzMtNSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgeT0iNTQuOTAxNDI0IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuODkyMiI+PHRzcGFuCiAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgQm9sZCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0IgogICBpZD0idHNwYW44OTI4Ij4yLjwvdHNwYW4+IFNQIGRldGVybWluZXMgSWRQLiBDcmVhdGVzPC90c3Bhbj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iMTA4LjQwOTYxIgogICAgICAgICB5PSI1OC44NzAxNzQiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW44OTI2Ij4mbHQ7QXV0aG5SZXF1ZXN0Jmd0OyBtZXNzYWdlIGFuZDwvdHNwYW4+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgeT0iNjIuODM4OTI0IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuODkyMCI+ZW1iZWRzIGl0IGluIFVSTCByZWRpcmVjdCB0byBJZFAuPC90c3Bhbj48L3RleHQ+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC40MDU2OTQ0MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO21hcmtlci1lbmQ6dXJsKCNtYXJrZXIxMDM2NykiCiAgICAgICBkPSJNIDE2OC4wMTQ1Niw3OC4wOTM2OTYgSCAzMy4zOTA2NDkiCiAgICAgICBpZD0icGF0aDkxNjYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNDA1Njk0NDM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjbWFya2VyOTkyOSkiCiAgICAgICBkPSJNIDMzLjIzNTkzNyw5Mi40NjE5MTIgSCAxNjcuNTUxNzMiCiAgICAgICBpZD0icGF0aDEwNTEzIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjQwNTY5NDQzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyLWVuZDp1cmwoI21hcmtlcjEwNTYxKSIKICAgICAgIGQ9Ik0gMTY3LjkyNDQsMTA3LjY1Mjg1IEggMjguOTcxMjYzIGwgMC4xMzI5MDQsOS40MzA0OCBoIDcxLjQzNzUwMyIKICAgICAgIGlkPSJwYXRoMTA1NTEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgeT0iNzUuNTM4OTQ4IgogICAgICAgaWQ9InRleHQ4MTczLTUtMSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjQxLjAwMzM3NiIKICAgICAgICAgeT0iNzUuNTM4OTQ4IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuODkyMC03Ij5Mb2dpbiBmb3JtIHNlbnQgdG8gdXNlcjwvdHNwYW4+PC90ZXh0PgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgeT0iODkuNTY2NjY2IgogICAgICAgaWQ9InRleHQ4MTczLTUtMS03Ij48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgICB5PSI4OS41NjY2NjYiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW44OTIwLTctNyI+VXNlciByZXBsaWVzIHdpdGggdXNlcmlkICZhbXA7IHBhc3N3b3JkPC90c3Bhbj48L3RleHQ+CiAgICA8dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSIxMDguNDA5NjEiCiAgICAgICB5PSI4Ni4yMDkyNTEiCiAgICAgICBpZD0idGV4dDgxNzMtNS0wIj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iMTA4LjQwOTYxIgogICAgICAgICB5PSI4Ni4yMDkyNTEiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW44OTIwLTEiPjx0c3BhbgogICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICBpZD0idHNwYW44OTI4LTUiPjMuPC90c3Bhbj4gSWRQIGF1dGhlbnRpY2F0ZXMgcHJpbmNpcGFsLjwvdHNwYW4+PC90ZXh0PgogICAgPGcKICAgICAgIGlkPSJnMTE5NTYiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS4wNTgzMzMzKSI+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTExMTEiCiAgICAgICAgIGQ9Ik0gMTA4LjQ3OTE3LDg1LjMzMzMzMyAxMDMuMTg3NSw4MC4wNDE2NjciCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC40MDU2OTQ0MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyLWVuZDp1cmwoI0Fycm93MU1lbmQpIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDExMTExLTgiCiAgICAgICAgIGQ9Ik0gMTA4LjQ3OTE3LDg1LjMzMzMzMyAxMDMuMTg3NSw5MC42MjUiCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC40MDU2OTQ0MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyLWVuZDp1cmwoI0Fycm93MU1lbmQtMSkiIC8+CiAgICA8L2c+CiAgICA8dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSIxMDguNDA5NjEiCiAgICAgICB5PSI5Ny4yMzQ3OTUiCiAgICAgICBpZD0idGV4dDgxNzMtNS0wNCI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgeT0iOTcuMjM0Nzk1IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuODkyMC0yIj48dHNwYW4KICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBCb2xkJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgaWQ9InRzcGFuODkyOC00Ij40LjwvdHNwYW4+IElkUCByZXNwb25kcyB3aXRoICZsdDtBc3NlcnRpb24mZ3Q7PC90c3Bhbj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iMTA4LjQwOTYxIgogICAgICAgICB5PSIxMDEuMjAzNTQiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW4xMTk5NCI+ZW1iZWRkZWQgaW4gZm9ybSB3aGljaDwvdHNwYW4+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgeT0iMTA1LjE3MjI5IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuMTE5OTYiPmF1dG9tYXRpY2FsbHkgcG9zdHMgdG8gU1AuPC90c3Bhbj48L3RleHQ+CiAgICA8cGF0aAogICAgICAgc3R5bGU9Im9wYWNpdHk6MTt2ZWN0b3ItZWZmZWN0Om5vbmU7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjQwNTY5NDQzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjbWFya2VyMTIwMDgpIgogICAgICAgZD0iTSAxMDAuNTQxNjcsMTMwLjMxMjUgSCAzNC4zOTU4MzMiCiAgICAgICBpZD0icGF0aDExOTk4IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI2NDU4MzMycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIHg9IjQxLjAwMzM3NiIKICAgICAgIHk9IjEyMy44NzE1NyIKICAgICAgIGlkPSJ0ZXh0ODE3My00Ij48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgICB5PSIxMjMuODcxNTciCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW44MTc1LTQiPjx0c3BhbgogICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICBpZD0idHNwYW44OTMwLTUiPjYuPC90c3Bhbj4gU1AgcmVwbGllcyB3aXRoIHJlZGlyZWN0IGZvcjwvdHNwYW4+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIHg9IjQxLjAwMzM3NiIKICAgICAgICAgeT0iMTI3Ljg0MDMyIgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgaWQ9InRzcGFuMTIxODIiPm9yaWdpbmFsIHJlc291cmNlIChSZWxheVN0YXRlKTwvdHNwYW4+PC90ZXh0PgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgaWQ9InBhdGgxMjE5MCIKICAgICAgIGQ9Im0gMzIuOTgwODc4LDE0My4zNjIyNSA2Ny4yNDMxMDIsLTAuMDcwNCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNDA1Njk0NDM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXItZW5kOnVybCgjbWFya2VyMTIxOTQpIiAvPgogICAgPHRleHQKICAgICAgIGlkPSJ0ZXh0MTM1MjYiCiAgICAgICB5PSIxMzcuNjI5NzkiCiAgICAgICB4PSI0MS4wMDMzNzYiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHRzcGFuCiAgICAgICAgIGlkPSJ0c3BhbjEzNTI0IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgeT0iMTM3LjYyOTc5IgogICAgICAgICB4PSI0MS4wMDMzNzYiCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiPjx0c3BhbgogICBpZD0idHNwYW4xMzUyMCIKICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBCb2xkJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQiPjcuPC90c3Bhbj4gU1AgYWNjZXNzZXMgcmVzb3VyY2UgYWdhaW48L3RzcGFuPjwvdGV4dD4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgaWQ9InBhdGgxMzUzOCIKICAgICAgIGQ9Ik0gMTAwLjU0MTY3LDE1Ni43NzEgSCAzNC4zOTU4MzMiCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO3ZlY3Rvci1lZmZlY3Q6bm9uZTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNDA1Njk0NDM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlci1lbmQ6dXJsKCNtYXJrZXIxMzU0MikiIC8+CiAgICA8dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSI0MS4wMDMzNzYiCiAgICAgICB5PSIxNTIuOTc1NDIiCiAgICAgICBpZD0idGV4dDE0MTE4Ij48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgeD0iNDEuMDAzMzc2IgogICAgICAgICB5PSIxNTIuOTc1NDIiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICBpZD0idHNwYW4xNDExNiI+PHRzcGFuCiAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgQm9sZCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0IgogICBpZD0idHNwYW4xNDExNCI+OC48L3RzcGFuPiBTUCByZXNwb25kcyB3aXRoIHJlc291cmNlPC90c3Bhbj48L3RleHQ+CiAgICA8dGV4dAogICAgICAgaWQ9InRleHQxNDEyOCIKICAgICAgIHk9IjExNi4yODQ3OSIKICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIj48dHNwYW4KICAgICAgICAgaWQ9InRzcGFuMTQxMjIiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICB5PSIxMTYuMjg0NzkiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSI+PHRzcGFuCiAgIGlkPSJ0c3BhbjE0MTIwIgogICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjMuMTc0OTk5OTVweDtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4Ij41LjwvdHNwYW4+IFNQIHZhbGlkYXRlcyAmbHQ7QXNzZXJ0aW9uJmd0OzwvdHNwYW4+PHRzcGFuCiAgICAgICAgIGlkPSJ0c3BhbjE0MTI2IgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgeT0iMTIwLjI1MzU0IgogICAgICAgICB4PSIxMDguNDA5NjEiCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiPmFuZCBjcmVhdGVzIHVzZXIgc2Vzc2lvbi48L3RzcGFuPjwvdGV4dD4KICAgIDxnCiAgICAgICBpZD0iZzE0MTcxIj4KICAgICAgPHJlY3QKICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuMTc2Mzg4ODk7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDE0MTMyIgogICAgICAgICB3aWR0aD0iNTIuNzM2MzY2IgogICAgICAgICBoZWlnaHQ9IjkuMzAzMTQ1NCIKICAgICAgICAgeD0iMTA2LjgxMDQ2IgogICAgICAgICB5PSIxMzMuNTQzNzYiIC8+CiAgICAgIDx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpzYW5zLXNlcmlmOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J3NhbnMtc2VyaWYsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHg9IjEwOC40MDk2MSIKICAgICAgICAgeT0iMTM3LjIzMjYiCiAgICAgICAgIGlkPSJ0ZXh0MTQxMzgiPjx0c3BhbgogICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgeD0iMTA4LjQwOTYxIgogICAgICAgICAgIHk9IjEzNy4yMzI2IgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTozLjE3NDk5OTk1cHg7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidzYW5zLXNlcmlmLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtzdHJva2Utd2lkdGg6MC4yNjQ1ODMzMnB4IgogICAgICAgICAgIGlkPSJ0c3BhbjE0MTM0Ij5JcyB0aGVyZSBhIHNlc3Npb24gZm9yIHRoaXMgdXNlcj88L3RzcGFuPjx0c3BhbgogICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgeD0iMTA4LjQwOTYxIgogICAgICAgICAgIHk9IjE0MS4yMDEzNSIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6My4xNzQ5OTk5NXB4O2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonc2Fucy1zZXJpZiwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7c3Ryb2tlLXdpZHRoOjAuMjY0NTgzMzJweCIKICAgICAgICAgICBpZD0idHNwYW4xNDEzNiI+WWVzLCB2YWxpZGF0ZSAmYW1wOyByZXR1cm4gcmVzb3VyY2UuPC90c3Bhbj48L3RleHQ+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K" alt="Web Browser SSO Profile">
|
|
</div>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">(1) HTTP Request to Service Provider</dt>
|
|
<dd>
|
|
<p>A user agent (e.g browser)
|
|
makes a request on behalf of a user for a protected resource hosted by
|
|
the Service Provider (e.g. Mellon). The SP asks if there is an
|
|
existing <a href="#saml_sessions">session</a> for the user. A session is
|
|
established by a prior successful SAML authentication. If a valid
|
|
session exists the SP immediately grants access to the protected
|
|
resource. A user session is communicated via a HTTP cookie (see
|
|
<a href="#mellon_cookie">Mellon Cookie</a>). If a valid session does not exist the SP begins
|
|
the authentication process.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(2) <AuthnRequest> issued by Service Provider to Identity Provider</dt>
|
|
<dd>
|
|
<p>To authenticate the user the SP must send a <code><AuthnRequest></code> to an
|
|
IdP. In the <em>Web Browser SSO Profile</em> the SP determines the IdP. The
|
|
SP uses the <em>HTTP Redirect Binding</em> to convey the <code><AuthnRequest></code> to
|
|
the IdP. This binding embeds the <code><AuthnRequest></code> in the URL query
|
|
parameters of a HTTP redirect. The browser performs a redirect to the
|
|
IdP which decodes the <code><AuthnRequest></code> embedded in the URL query
|
|
parameters. The IdP also maintains <a href="#saml_sessions">session</a>
|
|
information for the user. If there is an existing valid session for
|
|
the user at the IdP it immediately responds with a <code><Assertion></code>
|
|
response unless the <code><AuthnRequest></code> has enabled <code>ForceAuthn</code> which
|
|
requires the user to be re-authenticated. See the
|
|
<a href="#authentication_request">AuthnRequest example</a> to better understand
|
|
its contents and how it appears as HTTP data. Part of the data
|
|
communicated along with the <code><AuthnRequest></code> is an item known as the
|
|
<a href="#relaystate">RelayState</a>. The <code>RelayState</code> is the mechanism which
|
|
permits the flow to return to the original requested resource.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(3) Identity Provider identifies Principal</dt>
|
|
<dd>
|
|
<p>If necessary the IdP
|
|
authenticates the user. How the authentication is performed is <strong>not</strong>
|
|
defined by SAML. Typically the IdP responds with a login page where
|
|
the user enters their username and password. After successful
|
|
authentication the IdP establishes a session for the user.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(4) Identity Provider issues a SAML <Response> to the Service Provider</dt>
|
|
<dd>
|
|
<p>Assuming a valid session now exists on the IdP for the user
|
|
it responds to the user’s browser with an <code><Assertion></code> using the <em>HTTP
|
|
Post Binding</em>. The HTTP Post binding is a bit magical, you may want to
|
|
review how this works in <a href="#http_post">HTTP Post and Self-Posting</a>. If a valid session could not
|
|
be established for the user a failed status response is issued instead.
|
|
See the <a href="#assertion_response">Assertion example</a> to better understand
|
|
the contents of an <code><Assertion></code>.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(5) SP grants or denies access to the principal</dt>
|
|
<dd>
|
|
<p>If the response does not contain a successful <code><Assertion></code> response
|
|
the SP denies access by returning a 403 HTTP_FORBIDDEN status
|
|
response. Otherwise the SP processes the <code><Assertion></code>. The SP may
|
|
apply additional constraints on access to the protected resource (see
|
|
<a href="#assertion_constraints">Mellon constraints</a> for how Mellon can
|
|
apply additional authorization constraints). If the constraint check
|
|
passes then the SP establishes a session for the user. Mellon
|
|
associates the session information with a session ID returned in a
|
|
cookie (see <a href="#mellon_cookie">Mellon Cookie</a>).</p>
|
|
</dd>
|
|
<dt class="hdlist1">(6) SP redirects to original resource</dt>
|
|
<dd>
|
|
<p>The SP uses the <a href="#relaystate">RelayState</a> which identities the
|
|
original requested resource and responds with a redirect to that URL.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(7) Browser accesses resource again</dt>
|
|
<dd>
|
|
<p>The browser upon receiving the redirect to the original resource URL
|
|
once again tries to access the resource. This time however there is a
|
|
valid session established for the user as communicated in the session
|
|
cookie. The SP validates the session ID which should immediately
|
|
succeed. At this point Mellon informs Apache that the authentication
|
|
and authorization check has succeeded for the URL.</p>
|
|
</dd>
|
|
<dt class="hdlist1">(8) SP responds with resource</dt>
|
|
<dd>
|
|
<p>Since the authentication and authorization checks in Apache have now
|
|
passed the contents of the resource are returned to the user’s browser.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="saml_sessions">4.5.1. Sessions</h4>
|
|
<div class="paragraph">
|
|
<p>Sessions are maintained at both the SP and the IdP.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>After an IdP successfully authenticates a user it creates a session
|
|
for the user. The IdP keeps a list of every SP the user is logged
|
|
into. When the user logs out the IdP sends a logout request to the
|
|
<em>SingleLogoutService</em> endpoint of each SP. When an IdP receives a
|
|
<code><AuthnRequest></code> from a SP it checks to see if it has an existing
|
|
valid session for that user, if so it can skip authenticating the user
|
|
again and instead just issue an <code><Assertion></code> based on the existing
|
|
session. However the SP can force the IdP to always re-authenticate if
|
|
it passes a <code>ForceAuthn</code> value of <code>True</code> in the <code><AuthnRequest></code>. The
|
|
IdP may further be restricted from interacting with the SP if the
|
|
request contains a <code>isPassive</code> value of <code>True</code>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The IdP can inform the SP how long it wishes a SP session to be valid
|
|
by passing the <code>SessionNotOnOrAfter</code> attribute in a
|
|
<code><AuthnStatement></code>. Mellon respects the <code>SessionNotOnOrAfter</code>
|
|
attribute and will limit its session duration based on it.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The SP also maintains a session for the user. The SP session is
|
|
communicated between the browser and the SP using a cookie containing
|
|
the session ID. If the SP verifies the user has an existing valid
|
|
session when it receives a request it can immediately make an access
|
|
decision based on the cached session information for the user.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>See <a href="#mellon_session">Mellon Sessions</a> for more information on the
|
|
particulars of how Mellon manages it sessions.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="http_post">4.6. HTTP Post and Self-Posting</h3>
|
|
<div class="paragraph">
|
|
<p>The <em>HTTP Post Binding</em> is used to convey an assertion back to a
|
|
SP. Assertions are usually too big to embed in a URL so some other
|
|
mechanism is needed to transport the <code><Assertion></code> response data. The
|
|
data is url-form-encoded as HTTP Form. The form’s action attribute
|
|
specifies the destination URL of the form data.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Where does the destination URL come from? The IdP will have loaded the
|
|
SP’s <a href="#metadata">metadata</a> which defines among other things the
|
|
various provider URL <a href="#endpoints">endpoints</a> where SAML communication
|
|
occurs. The <code><Assertion></code> needs to be sent to one of the SP’s
|
|
<em>AssertionConsumerService</em> endpoints, specifically the
|
|
<em>AssertionConsumerService</em> endpoint URL supporting the <em>HTTP-POST</em>
|
|
binding. The SP’s <em>AssertionConsumerService</em> URL as read from its
|
|
metadata is set to the action attribute of the HTTP form. <em>The action
|
|
URL is <strong>not</strong> read from any data in the <AuthnRequest></em>, this is one
|
|
safeguard to prevent SAML messages from being sent to a unintended
|
|
nefarious party. Note that many SAML bindings define a <code>Destination</code>
|
|
attribute that is embedded in the SAML message. A further check
|
|
compares the <code>Destination</code> attribute to the URL the message was
|
|
received at, see <a href="#invalid_destination">HTTP_BAD_REQUEST - Invalid Destination on Response</a> for a common deployment
|
|
problem.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>But how does the POST data as received by the user’s browser get back
|
|
to the <em>AssertionConsumerService</em> endpoint of the SP? The form will
|
|
<em>self-post</em> due to this:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-html" data-lang="html"><body onload="document.forms[0].submit()"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>As long as the user’s browser has not disabled scripts it will
|
|
immediately post the form data to the <em>AssertionConsumerService</em> URL
|
|
in the forms action attribute. If scripts have been disabled the HTML
|
|
will instruct the user to click the <code>Submit</code> button to post the form
|
|
data.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="entityID">4.7. entityID</h3>
|
|
<div class="paragraph">
|
|
<p>Each SAML provider (e.g. a SP or IdP) is identified by its
|
|
<code>entityID</code>. You should think of the <code>entityID</code> as the globally unique
|
|
name of the provider. The <code>entityID</code> appears in most SAML messages and
|
|
in the provider’s metadata. This is the mechanism by which a SAML
|
|
message consumer associates the SAML message with the message
|
|
producers configuration properties. When a SAML provider receives a
|
|
message it extracts the <code>entityID</code> from the message and then looks up
|
|
the metadata belonging to that provider. The information in the
|
|
provider’s metadata is essential in order to operate on the SAML
|
|
message.</p>
|
|
</div>
|
|
<div class="admonitionblock warning">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-warning" title="Warning"></i>
|
|
</td>
|
|
<td class="content">
|
|
Any mismatch between the <code>entityID</code> the producer is emitting
|
|
and the consumer has loaded via the producer’s metadata will cause
|
|
failures. A common mistake is to modify a producer’s metadata
|
|
(e.g. update Mellon) but fail to reload Mellon’s metadata in the IdP.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>SAML places two requirements on the <code>entityID</code>:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>It <strong>must</strong> be an URI</p>
|
|
</li>
|
|
<li>
|
|
<p>It <strong>must</strong> be unique within the federation</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>A wise administrator will also seek to fulfill this additional
|
|
requirement when choosing an <code>entityID</code>:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>It should identify the organization instead of a specific node
|
|
within the organization.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When migration time arrives it is far easier to move resources around
|
|
when those resources are not tied to a specific node. Thus choosing an
|
|
<code>entityID</code> comprised of the organization’s domain name and a generic
|
|
identifier such as <code>saml</code> would be one good approach, for example
|
|
<code><a href="https://bigcorp.com/saml" class="bare">https://bigcorp.com/saml</a></code>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>A common practice and one that recommended in the
|
|
<a href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf">Metadata
|
|
for the OASIS Security Assertion Markup Language (SAML)</a> specification
|
|
in section 4, <em>Metadata Publication and Resolution</em> is to use the
|
|
<code>entityID</code> as a <em>well-known-location</em> for retrieving the provider’s
|
|
metadata. In other words the <code>entityID</code> is the URL which returns the
|
|
provider’s XML metadata document when a HTTP GET is performed on that
|
|
URL. <em>It is not a requirement the <code>entityID</code> be the URL for metadata
|
|
download</em> rather it is one common convention. As discussed in the SAML
|
|
metadata specification other mechanisms can be established for
|
|
metadata publication.</p>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
SAML requires metadata publication to be integrity
|
|
protected. A provider’s metadata is literally the <em>keys to the
|
|
provider’s kingdom</em> as it contains the cryptographic keys used during
|
|
SAML authentication as well as other vital SAML properties. <em>It is
|
|
essential to establish trust and validate the metadata.</em> Metadata can
|
|
be signed but the easiest way to assure metadata integrity and the
|
|
most common is to make sure metadata is only exchanged via a secure
|
|
and trusted channel. TLS provides such a mechanism. Therefore if you
|
|
publish metadata (and Mellon always does regardless of whether Mellon’s
|
|
metadata endpoint matches Mellon’s <code>entityID</code>) it <strong><em>MUST</em></strong> occur
|
|
<em>only</em> over the <code>https</code> TLS scheme. Make sure your Apache
|
|
configuration redirects any <code>http</code> for Mellon to <code>https</code> and that your
|
|
https certificate is signed by a trusted CA such that others can
|
|
properly validate your https cert. <em>Do not use self-signed certs for
|
|
your https!</em> If you do and you’re on a public network, you’re
|
|
opening yourself up to a serious security vulnerability. Note, the
|
|
certs used <em>inside</em> the metadata can be self-signed, see
|
|
<a href="#metadata_keys">Certs and Keys Inside Metadata</a> for an explanation of why. The key concept here to take
|
|
away is that <em>a provider’s metadata provides the trust and is the validation
|
|
mechanism used by SAML</em>. Thus the integrity of the metadata is of
|
|
paramount importance.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon’s metadata is <em>always</em> published at the URL location
|
|
<code>/$MellonEndpointPath/metadata</code>. See the description of
|
|
<a href="#mellon_endpoint_path">MellonEndpointPath</a> for more details on the
|
|
use of MellonEndpointPath. This is why most of the tools surrounding
|
|
Mellon generate an <code>entityID</code> as the concatenation of the https
|
|
scheme, the hostname, the MellonEndpointPath and "metadata". Thus for
|
|
example if the <code>MellonEndpointPath</code> for <code>bigcorp.com</code> was set to
|
|
<code>saml</code>, the <code>entityID</code> (the URL location for downloading its
|
|
metadata) would be <code><a href="https://bigcorp.com/saml/metadata" class="bare">https://bigcorp.com/saml/metadata</a></code>. The only reason
|
|
why "metadata" appears in the <code>entityID</code> is because that is Mellon’s
|
|
URL endpoint for metadata publication.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="name_id">4.8. Username, userid, SAML NameID</h3>
|
|
<div class="sect3">
|
|
<h4 id="_userid_vs_identity_or_why_userid_is_so_last_millennium">4.8.1. Userid vs. Identity (or why userid is so last millennium)</h4>
|
|
<div class="paragraph">
|
|
<p>Many people struggle with the notion of <em>userid</em> when working with
|
|
SAML (or any other federated identity system). That’s because
|
|
historically <em>userid</em> has been used to describe <em>identity</em>. The two
|
|
are not the same. <em>Identity</em> identifies who or what something is for
|
|
the purpose of authentication and authorization as well as binding
|
|
attributes to that identity. In most of the literature the terms
|
|
<em>subject</em> and <em>principal</em> are used interchangeably to encapsulate the
|
|
concept of who or what is being identified. Although a
|
|
subject is often a person it need not be, it might also be an
|
|
inanimate object. A good example of a non-human subject would be a
|
|
computer service needing to be authenticated in order to perform
|
|
an operation.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Userids grew out of the early days of computing when all computing
|
|
was local and users were given accounts on a local system. The userid
|
|
was how operating systems tracked who a user was, in most cases it was
|
|
an integer. Clearly the integer userid only had meaning in the context
|
|
of the local system. As systems became networked integer userids
|
|
would be shared between systems but fundamentally nothing had changed,
|
|
the userid was still meaningful only among a group of cooperating
|
|
computers. Tools such as Yellow Pages, NIS, LDAP and Active Directory
|
|
were developed to provide a centralized repository of userids that
|
|
could be shared between cooperating networked computers. Along the way
|
|
the integer userid morphed into a string often partitioned into a
|
|
local part and a domain part. The domain part is used to identify the
|
|
realm. Realms are nothing other than collections of <em>unique</em> userids
|
|
often serving the needs of a organizational unit (e.g. company or
|
|
institution).</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>A key concept is that whoever is providing the userid, whether it be local
|
|
accounts created by the host operating system or a network provider of
|
|
userids such as NIS or LDAP, is an <strong>identity provider</strong> (IdP) with the
|
|
<em>userid</em> being the <strong>key</strong> used by <em>that</em> specific
|
|
<strong>identity provider</strong> to look up the <strong>identity</strong>. Hence <em>userids are only
|
|
meaningful in the context of a specific IdP!</em></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>By definition <em>federated identity</em> is the amalgamation of diverse
|
|
unrelated identity providers, each of which utilizes its own userid as
|
|
a key to look up an identity. Therefore while deploying federated
|
|
identity if you cling to the concept of a single userid you are likely to
|
|
be frustrated because you are abusing the concept.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="saml_nameid">4.8.2. How SAML identifies a subject</h4>
|
|
<div class="paragraph">
|
|
<p>In SAML the user name (principal or subject) is conveyed as part of
|
|
the <code><Subject></code> element in the assertion. The subject identifier can
|
|
be any one of these elements:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code><BaseID></code></p>
|
|
</li>
|
|
<li>
|
|
<p><code><NameID></code></p>
|
|
</li>
|
|
<li>
|
|
<p><code><EncryptedID></code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The most common is <code><NameID></code> and it usually includes a <code>Format</code>
|
|
attribute. If the <code>Format</code> attribute is absent then it defaults to the
|
|
unspecified <code>Format</code>. The <code>Format</code> attribute tells you how to interpret
|
|
the <code>NameID</code> value. For example if the subject’s <code>NameID</code> format is
|
|
<code>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</code> you know the
|
|
subject is being identified by their email address.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The currently defined <code>NameID</code> formats are:</p>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">Unspecified</dt>
|
|
<dd>
|
|
<p>This is used when you don’t care what the <code>NameID</code> <code>Format</code> is, you’re
|
|
willing to accept whatever it defaults to by the provider.
|
|
(<code>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">Email Address</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is an email address as specified in RFC 2822 as a
|
|
<code>addr-spec</code> in the form <code>local-part@domain</code>. No common name
|
|
or other text is included and it is not enclosed in <code><</code> and <code>></code>.
|
|
(<code>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">X.509 Subject Name</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is an X.509 subject name in the form specified for the
|
|
<code><ds:X509SubjectName></code> element in the XML Signature Recommendation.
|
|
(<code>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">Windows Domain Qualified Name</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is a Windows domain qualified name. A Windows domain
|
|
qualified user name is a string of the form "DomainName\UserName". The
|
|
domain name and "\" separator MAY be omitted.
|
|
(<code>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">Kerberos Principal Name</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is in the form of a Kerberos principal name using the
|
|
format name[/instance]@REALM.
|
|
(<code>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">Persistent Identifier</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is a <em>persistent</em> opaque
|
|
identifier for a principal that is specific to an identity provider
|
|
and a service provider or affiliation of service providers. Opaque
|
|
means you cannot (easily) map the id to a user. In many cases the
|
|
persistent id is implemented as a random number or random
|
|
string. Persistent means you’ll always get the exact same <code>NameID</code> for
|
|
the same subject. Refer to <a href="#nameid_policy">NameIDPolicy</a> and its
|
|
<code>AllowCreate</code> attribute to understand if the IdP is allowed to create
|
|
a persistent id for the subject if it has not already done so.
|
|
(<code>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</code>)</p>
|
|
</dd>
|
|
<dt class="hdlist1">Transient Identifier</dt>
|
|
<dd>
|
|
<p>The <code>NameID</code> is an opaque <em>temporary</em> id. Opaque means you cannot
|
|
(easily) map the id to a user. In many cases it’s implemented as a
|
|
random number or random string. Temporary means the id is valid <em>only</em> in the
|
|
context of the assertion response which contains it. Think of a
|
|
transient id as a one-time id that cannot be used again or referred to
|
|
again.
|
|
(<code>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</code>)</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
The important concept here is that SAML’s <code>NameID</code> as used to
|
|
identify a subject is not the traditional userid you are probably
|
|
used to. Furthermore SAML’s <code>NameID</code> <em>may</em> only be meaningful to the IdP
|
|
which issued it.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="nameid_interpretation">4.8.3. Burden of interpreting NameID falls to the relying party</h4>
|
|
<div class="paragraph">
|
|
<p>Ultimately the SP needs to provide some sort of <em>userid</em> the
|
|
application it is hosting can utilize. <em>Only the application knows what it
|
|
needs!</em></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Let’s take the example of an application which wishes to
|
|
identify its users by email address. There are two basic ways you can
|
|
do this with SAML.</p>
|
|
</div>
|
|
<div class="olist arabic">
|
|
<ol class="arabic">
|
|
<li>
|
|
<p>Specify a <code>NameIDPolicy</code> of
|
|
<code>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</code> when the SP
|
|
submits a <code><AuthnRequest></code> to the IdP. This tells the IdP you want the
|
|
subject’s <code>NameID</code> to be their email address.</p>
|
|
</li>
|
|
<li>
|
|
<p>Ignore the <code>NameID</code> returned in the assertion entirely, instead use
|
|
the assertion’s <code>email</code> attribute.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Solution #2 is very important to understand as it illustrates how many
|
|
organizations utilize SAML: they <em>build an identity from the
|
|
attributes bound to a subject</em>. They can use one or more attributes to
|
|
build a userid meaningful to the application. They may even require
|
|
the IdP return an attribute unique to the subject across a federation,
|
|
in this instance all IdPs in the federation must support that
|
|
attribute (this is just one approach). The <code>NameID</code> is <strong>not</strong> utilized
|
|
in solution #2 in large part because the <code>NameID</code> is likely to be
|
|
uniquely bound to the given IdP. This is why SAML’s <em>transient</em>
|
|
identifiers are often used: it simply does not matter what the
|
|
<code>NameID</code> is because the SP is not utilizing it therefore it can be any
|
|
random one-time value.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>It is also important to understand either the <code>NameID</code> <em>or</em> the set of
|
|
attributes <em>or both</em> can be used to ultimately derive an identity to
|
|
pass to the application.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Another approach is to utilize SAML’s <em>persistent id</em> with the
|
|
observation that the pair (IdP, persistent id) always uniquely
|
|
and repeatably identifies the subject. The SP can maintain a table
|
|
that maps the (IdP, persistent id) pair to an
|
|
application-specific <em>identity</em> using this technique.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_how_mellon_handles_the_nameid">4.8.4. How Mellon handles the NameID</h4>
|
|
<div class="paragraph">
|
|
<p>Mellon extracts the <code><NameID></code> element from the
|
|
assertion’s <code><Subject></code> element and sets this to <code>NAME_ID</code> attribute. If
|
|
<code><NameID></code> is absent in the assertion you can change what Mellon
|
|
considers the user name to be to another value in one of the
|
|
assertions attributes if you wish. <code>MellonUser</code> names the attribute
|
|
you wish to use instead. If you want to export the username as
|
|
<code>REMOTE_USER</code> so your web app can process this very common CGI
|
|
variable see <a href="#set_remote_user">How to set REMOTE_USER</a></p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
Please be aware that blindly exporting the SAML <code>NameID</code> to the
|
|
application may or may not be appropriate for the application. See the
|
|
explanation of <a href="#nameid_interpretation">NameID interpretation</a> to
|
|
understand the issues.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="specify_mellon_nameid">4.8.5. How do you specify the NameID format in SAML?</h4>
|
|
<div class="paragraph">
|
|
<p>In SAML there are 2 configuration options related to the use of
|
|
<code>NameID</code>:</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>1. A provider declares which <code>NameID</code> formats it supports in its
|
|
<a href="#metadata">metadata</a> via the <code><NameIDFormat></code> element.
|
|
The following metadata excerpt illustrates a provider
|
|
which supports the <code>transient</code>, <code>persistent</code> and <code>X509SubjectName</code>
|
|
formats:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><NameIDFormat>
|
|
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
|
</NameIDFormat>
|
|
<NameIDFormat>
|
|
urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
|
</NameIDFormat>
|
|
<NameIDFormat>
|
|
urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
|
</NameIDFormat></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>2. The SP indicates to the IdP in its <code><AuthnRequest></code> what <code>NameID</code>
|
|
format it wants returned via the <code><NameIDPolicy></code> element. The
|
|
<code><NameIDPolicy></code> should be one of the <code>NameIDFormat</code> elements
|
|
enumerated in the IdP’s metadata. The IdP is free to substitute
|
|
another <code>NameID</code> format or to return an <code>InvalidNameIDPolicy</code> error
|
|
status response if it can’t satisfy the request. <a id="nameid_policy"></a></p>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
Mellon defaults to a <code>NameIDFormat</code> of <code>transient</code> when it
|
|
<a href="#metadata_creation">generates its metadata</a>. You will need to
|
|
manually edit the <code>NameIDFormat</code> in your Mellon SP metadata if you
|
|
wish to use a <code>NameIDFormat</code> other than <code>transient</code>. When Mellon
|
|
generates its <code><AuthnRequest></code> it selects the <em>first</em> <code>NameIDFormat</code>
|
|
found in its metadata as the <code>NameIDPolicy</code>.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="authentication_request">4.9. <AuthnRequest> Example</h3>
|
|
<div class="paragraph">
|
|
<p>Here is an example <code><AuthnRequest></code> as emitted by Mellon.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
ID="_59126C3306E4679F653022F0C4DA7F04" <i class="conum" data-value="1"></i><b>(1)</b>
|
|
Version="2.0"
|
|
IssueInstant="2017-06-28T13:39:14Z" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
Destination="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" <i class="conum" data-value="3"></i><b>(3)</b>
|
|
Consent="urn:oasis:names:tc:SAML:2.0:consent:current-implicit"
|
|
ForceAuthn="false" <i class="conum" data-value="4"></i><b>(4)</b>
|
|
IsPassive="false" <i class="conum" data-value="5"></i><b>(5)</b>
|
|
AssertionConsumerServiceURL="https://mellon.example.com/mellon/postResponse" <i class="conum" data-value="6"></i><b>(6)</b>
|
|
>
|
|
<saml:Issuer>https://mellon.example.com/mellon/metadata</saml:Issuer> <i class="conum" data-value="7"></i><b>(7)</b>
|
|
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" <i class="conum" data-value="8"></i><b>(8)</b>
|
|
AllowCreate="true"/> <i class="conum" data-value="9"></i><b>(9)</b>
|
|
</samlp:AuthnRequest></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>ID</code>: Unique ID generated by Mellon to identify the SAML
|
|
request. It will appear in the SAML response in the <code>InResponseTo</code>
|
|
attribute. Used to correlate SAML request and responses.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td><code>IssueInstant</code>: Timestamp of when request was made</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td><code>Destination</code>: Where this request was sent to. Used as a
|
|
protection to prevent malicious forwarding of requests to unintended
|
|
recipients. The recipient verifies the URL where it received the SAML
|
|
request matches the <code>Destination</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td><code>ForceAuthn</code>: If true the IdP <strong>must</strong> authenticate the principal
|
|
instead of relying on an existing session for the principal.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td><code>IsPassive</code>: If true neither the user agent (browser) nor the IdP
|
|
may take control of the user interface.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td><code>AssertionConsumerServiceURL</code>: Where to send the assertion
|
|
response (see <a href="#sp_metadata_acs">SP metadata AssertionConsumerService
|
|
for HTTP-POST binding</a> to see where this was defined.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="7"></i><b>7</b></td>
|
|
<td><code>Issuer</code>: The SP which issued the AuthnRequest. See
|
|
<a href="#sp_metadata_entityid">SP metadata Issuer</a> to see where this was
|
|
defined. Also see the general description of <a href="#entityId">SAML Entity ID’s</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="8"></i><b>8</b></td>
|
|
<td><code>NameIDPolicy</code>: The SP requests that the Subject returned in the
|
|
assertion be identified by a transient name. See <a href="#name_id">Username, userid, SAML NameID</a> for more
|
|
details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="9"></i><b>9</b></td>
|
|
<td><code>AllowCreate</code>: If true then the IdP is allowed to create a new
|
|
identifier for the principal.</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The <code><AuthnRequest></code> is sent using the <em>HTTP Redirect Binding</em>. The
|
|
above <code><AuthnRequest></code> appears on the wire as a URL with the SAML
|
|
data embedded as query parameters. You can see the "on the wire" HTTP
|
|
data for this <code><AuthnRequest></code> in
|
|
<a href="#authentication_request_wire">Example On-The-Wire AuthnRequest</a>. This illustrates the need for SAML
|
|
diagnostic tools because you cannot see the <code><AuthnRequest></code> XML
|
|
message and its assocated data (e.g. signature, <a href="#relaystate">RelayState</a>) by looking at the HTTP protocol.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="assertion_response">4.10. <Assertion> Example</h3>
|
|
<div class="paragraph">
|
|
<p>This is an example of an <code><Assertion></code> response as generated by a Red
|
|
Hat SSO server (Keycloak) in response to the above
|
|
<a href="#authentication_request"><AuthnRequest> Example</a>.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" <i class="conum" data-value="1"></i><b>(1)</b>
|
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
Destination="https://mellon.example.com/mellon/postResponse" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
ID="ID_d06daaaf-64ec-44d3-95a7-08da893aa9d5" <i class="conum" data-value="3"></i><b>(3)</b>
|
|
InResponseTo="_59126C3306E4679F653022F0C4DA7F04" <i class="conum" data-value="4"></i><b>(4)</b>
|
|
IssueInstant="2017-06-28T13:39:27.331Z" <i class="conum" data-value="5"></i><b>(5)</b>
|
|
Version="2.0">
|
|
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://rhsso.example.com:8443/auth/realms/test</saml:Issuer> <i class="conum" data-value="6"></i><b>(6)</b>
|
|
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> <i class="conum" data-value="7"></i><b>(7)</b>
|
|
<dsig:SignedInfo>
|
|
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
|
<dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
|
|
<dsig:Reference URI="#ID_d06daaaf-64ec-44d3-95a7-08da893aa9d5"> <i class="conum" data-value="8"></i><b>(8)</b>
|
|
<dsig:Transforms>
|
|
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
|
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
|
</dsig:Transforms>
|
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
|
|
<dsig:DigestValue>V/3iYohGv2Ot7pzy6q/BfAdXgSxmdCD7K+XEmFIZlUs=</dsig:DigestValue>
|
|
</dsig:Reference>
|
|
</dsig:SignedInfo>
|
|
<dsig:SignatureValue>...</dsig:SignatureValue>
|
|
<dsig:KeyInfo>
|
|
<dsig:KeyName>1VPndjfABB6S4lb4zwMLjBUhxfzPFnfrvNYvRgcxiUM</dsig:KeyName>
|
|
<dsig:X509Data>
|
|
<dsig:X509Certificate>...</dsig:X509Certificate>
|
|
</dsig:X509Data>
|
|
<dsig:KeyValue>
|
|
<dsig:RSAKeyValue>
|
|
<dsig:Modulus>...</dsig:Modulus>
|
|
<dsig:Exponent>AQAB</dsig:Exponent>
|
|
</dsig:RSAKeyValue>
|
|
</dsig:KeyValue>
|
|
</dsig:KeyInfo>
|
|
</dsig:Signature>
|
|
<samlp:Status> <i class="conum" data-value="9"></i><b>(9)</b>
|
|
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
|
|
</samlp:Status>
|
|
<saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" <i class="conum" data-value="10"></i><b>(10)</b>
|
|
ID="ID_c463a141-d471-40c3-860a-6559ce0a3556"
|
|
IssueInstant="2017-06-28T13:39:27.331Z"
|
|
Version="2.0"
|
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
|
|
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://rhsso.example.com:8443/auth/realms/test</saml:Issuer> <i class="conum" data-value="11"></i><b>(11)</b>
|
|
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> <i class="conum" data-value="12"></i><b>(12)</b>
|
|
<dsig:SignedInfo>
|
|
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
|
<dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
|
|
<dsig:Reference URI="#ID_c463a141-d471-40c3-860a-6559ce0a3556"> <i class="conum" data-value="13"></i><b>(13)</b>
|
|
<dsig:Transforms>
|
|
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
|
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
|
</dsig:Transforms>
|
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
|
|
<dsig:DigestValue>w8bELRshtX7xHcwZCdglgfpyYBMJmVQJALPAclHHbLA=</dsig:DigestValue>
|
|
</dsig:Reference>
|
|
</dsig:SignedInfo>
|
|
<dsig:SignatureValue>...</dsig:SignatureValue>
|
|
<dsig:KeyInfo>
|
|
<dsig:KeyName>1VPndjfABB6S4lb4zwMLjBUhxfzPFnfrvNYvRgcxiUM</dsig:KeyName>
|
|
<dsig:X509Data>
|
|
<dsig:X509Certificate>...</dsig:X509Certificate>
|
|
</dsig:X509Data>
|
|
<dsig:KeyValue>
|
|
<dsig:RSAKeyValue>
|
|
<dsig:Modulus>...</dsig:Modulus>
|
|
<dsig:Exponent>AQAB</dsig:Exponent>
|
|
</dsig:RSAKeyValue>
|
|
</dsig:KeyValue>
|
|
</dsig:KeyInfo>
|
|
</dsig:Signature>
|
|
<saml:Subject> <i class="conum" data-value="14"></i><b>(14)</b>
|
|
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" <i class="conum" data-value="15"></i><b>(15)</b>
|
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
|
|
G-803528aa-2f9e-454b-a89c-55ee74e75d1e
|
|
</saml:NameID>
|
|
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
|
<saml:SubjectConfirmationData InResponseTo="_59126C3306E4679F653022F0C4DA7F04"
|
|
NotOnOrAfter="2017-06-28T13:44:25.331Z"
|
|
Recipient="https://mellon.example.com/mellon/postResponse"/>
|
|
</saml:SubjectConfirmation>
|
|
</saml:Subject>
|
|
<saml:Conditions NotBefore="2017-06-28T13:39:25.331Z"
|
|
NotOnOrAfter="2017-06-28T13:40:25.331Z">
|
|
<saml:AudienceRestriction>
|
|
<saml:Audience>https://mellon.example.com/mellon/metadata</saml:Audience>
|
|
</saml:AudienceRestriction>
|
|
</saml:Conditions>
|
|
<saml:AuthnStatement AuthnInstant="2017-06-28T13:39:27.332Z"
|
|
SessionIndex="9b6a46b9-28f2-4ce1-b151-713240520e5d">
|
|
<saml:AuthnContext>
|
|
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
|
|
</saml:AuthnContext>
|
|
</saml:AuthnStatement>
|
|
<saml:AttributeStatement> <i class="conum" data-value="16"></i><b>(16)</b>
|
|
<saml:Attribute FriendlyName="List of groups" <i class="conum" data-value="17"></i><b>(17)</b>
|
|
Name="groups"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" <i class="conum" data-value="18"></i><b>(18)</b>
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">ipausers</saml:AttributeValue>
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" <i class="conum" data-value="18"></i><b>(18)</b>
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">openstack-users</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute FriendlyName="email"
|
|
Name="email"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"`>
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">jdoe@music.com</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute FriendlyName="Display Name"
|
|
Name="display_name"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">John Doe</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute FriendlyName="initials"
|
|
Name="initials"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">JD</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute FriendlyName="Last Name"
|
|
Name="last_name"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">Doe</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute FriendlyName="First Name"
|
|
Name="first_name"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">John</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute Name="Role"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">uma_authorization</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute Name="Role"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">manage-account</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
<saml:Attribute Name="Role"
|
|
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:type="xs:string">view-profile</saml:AttributeValue>
|
|
</saml:Attribute>
|
|
</saml:AttributeStatement>
|
|
</saml:Assertion>
|
|
</samlp:Response></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>Response</code>: The <code><Response></code> element contains the entire SAML
|
|
response, which includes information concerning who issued the
|
|
response, when the response was issued, optionally a signature on the
|
|
response, and the actual response contents which in this case is an
|
|
<code><Assertion></code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td><code>Destination</code>: The <em>AssertionConsumerService</em> endpoint where this
|
|
response will be sent. The receiver will verify it arrived at this
|
|
location or it will reject it.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td><code>ID</code>: Unique ID generated by Mellon to identify the SAML
|
|
request. It will appear in the SAML response in the <code>InResponseTo</code>
|
|
attribute. Used to correlate SAML request and responses.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td><code>InResponseTo</code>: This identifies the SAML request being responded
|
|
to. It matches the <code>ID</code> attribute in the
|
|
<a href="#authentication_request"><AuthnRequest> Example</a>. This is how SAML requests and responses are
|
|
associated with one another as a pair.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td><code>IssueInstant</code>: Timestamp of when response was made.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td><code>Issuer</code>: The IdP which is issuing this response. It is the
|
|
<a href="#entityID">entityID</a> of the IdP as defined in the <a href="#idp_metadata">Identity Provider Metadata</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="7"></i><b>7</b></td>
|
|
<td><code>Signature</code>: This response is signed by the IdP. The signature
|
|
information is contained in this XML element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="8"></i><b>8</b></td>
|
|
<td><code>Reference</code>: Identifies the XML element being signed. In this
|
|
instance since the signature reference points to the top level
|
|
<code><samlp:Response></code> the entire response is signed.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="9"></i><b>9</b></td>
|
|
<td><code>Status</code>: The status of the SAML response. Because in this
|
|
instance the status is <code>urn:oasis:names:tc:SAML:2.0:status:Success</code>,
|
|
the authentication was successful. If it had not been, an error status
|
|
would have been returned. <strong>The <Status> element is where to look for the
|
|
success or failure of a SAML request.</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="10"></i><b>10</b></td>
|
|
<td><code>Assertion</code>: This begins the assertion data. It represents the
|
|
<em>content</em> of the SAML response.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="11"></i><b>11</b></td>
|
|
<td><code>Issuer</code>: The IdP which is issuing this response. It is the
|
|
<a href="#entityID">entityID</a> of the IdP as defined in the <a href="#idp_metadata">Identity Provider Metadata</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="12"></i><b>12</b></td>
|
|
<td><code>Signature</code>: The signature on the <code><Assertion></code>. Note this is
|
|
independent of the signature on the response.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="13"></i><b>13</b></td>
|
|
<td><code>Reference</code>: Identifies the XML element being signed. In this
|
|
instance the signature reference points to the <code><Assertion></code> element,
|
|
because that element has the matching <code>ID</code> attribute.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="14"></i><b>14</b></td>
|
|
<td><code>Subject</code>: This begins the <code><Subject></code> element which identifies
|
|
the principal being authenticated in this <code><Assertion></code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="15"></i><b>15</b></td>
|
|
<td><code>NameID</code>: <strong>This is where Mellon obtains the username in the
|
|
assertion.</strong> Because the format is <code>transient</code> it is a random value
|
|
assigned by the IdP. Note the <code>MELLON_NAME_ID</code> in the Apache
|
|
environment exactly matches this. See <a href="#name_id">Username, userid, SAML NameID</a> for more details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="16"></i><b>16</b></td>
|
|
<td><code>AttributeStatement</code>: This begins the <strong>set of attributes</strong> supplied
|
|
by the IdP.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="17"></i><b>17</b></td>
|
|
<td><code>Attribute</code>: This is the attribute whose <code>name</code> is <em>groups</em>. It is a
|
|
multi-valued attribute because it contains 2 <code><AttributeValue></code>
|
|
elements. This attribute could be written in pseudo-code as
|
|
<code>groups=["ipausers","openstack-users"]</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="18"></i><b>18</b></td>
|
|
<td><code>AttributeValue</code>: These are the values for the attribute. In this
|
|
instance there are 2 values, <em>ipausers</em> and <em>openstack-users</em>.</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The above <code><Assertion></code> response is conveyed back to the SP using the
|
|
<em>HTTP Post Binding</em>. You may wish to review <a href="#http_post">HTTP Post and Self-Posting</a>. The "on the
|
|
wire" version of this <code><Assertion></code> response and its associated
|
|
parameters can be seen in <a href="#assertion_response_wire">Example On-the-Wire <Assertion> response</a>. Once again we see
|
|
the need for SAML tools because it is impossible to view the XML
|
|
message and its associated parameters give the contents of the HTTP
|
|
response.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="endpoints">4.11. SAML Endpoints</h3>
|
|
<div class="paragraph">
|
|
<p>When two SAML providers communicate they must know the URL to send a
|
|
given SAML message to. The set of URLs where a provider receives SAML
|
|
messages is often referred to as its SAML endpoints. Although a SAML
|
|
endpoint may appear in a SAML message, this is <strong>not sufficient</strong> to
|
|
identify where a response should be sent. This is because a nefarious
|
|
sender could insert a bogus location in the message. To assure SAML
|
|
messages are only exchanged between the expected parties, the message
|
|
endpoints are established outside of the message exchange via a
|
|
trusted mechanism when a relationship is initially established between
|
|
the two providers. Although not mandated, this is almost always
|
|
accomplished via the exchange of SAML <a href="#metadata">metadata</a> forming a
|
|
trust relationship between the two providers. The presence of a SAML
|
|
endpoint in a SAML message is typically there to validate the message
|
|
against the previously established trust information. Also as you will
|
|
learn below, an endpoint must be paired with a binding type, which is
|
|
another reason why an endpoint appearing in a SAML message is not
|
|
sufficient to establish a communication pathway.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>A SAML endpoint is defined by a (service,binding)
|
|
pair. The service component identifies what action is hosted by this
|
|
endpoint. Examples of common SAML services you are likely to encounter
|
|
are:</p>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">SingleSignOnService</dt>
|
|
<dd>
|
|
<p>Authenticate a user and establish a session for them. This is an IdP
|
|
service, it’s where a SP sends its <code><AuthnRequest></code> message.</p>
|
|
</dd>
|
|
<dt class="hdlist1">AssertionConsumerService</dt>
|
|
<dd>
|
|
<p>This is where SPs receive <code><Assertion></code> messages from an IdP in
|
|
response to a <code><AuthnRequest></code> message.</p>
|
|
</dd>
|
|
<dt class="hdlist1">SingleLogoutService</dt>
|
|
<dd>
|
|
<p>Terminate a user’s session by logging them out. Both SPs and IdPs
|
|
support this.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The binding component of a (service,binding) pair identifies the format
|
|
of the message. Recall that SAML offers many different ways to encode
|
|
the XML of a SAML message. The binding component allows the receiver
|
|
to know how to decode and parse the SAML message back into an XML SAML
|
|
document received at its service endpoint.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>It’s important to understand there is no requirement for a SAML
|
|
provider to locate all its (service,binding) pairs on distinct
|
|
URLs. It is possible to apply heuristics to a SAML message to
|
|
identify the binding of the message arriving on a given URL. This
|
|
allows a provider to collapse its set of endpoints into a smaller set
|
|
of URLs The choice of how a provider maps its endpoints to URLs is
|
|
entirely up to the provider. A common mistake is to assume that because
|
|
one provider does it one way all providers follow the same model. The
|
|
only way for you to know is to examine the providers metadata (see
|
|
<a href="#metadata">The Role of Metadata</a>)</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="relaystate">4.12. Relay State (How you return to the original URL)</h3>
|
|
<div class="paragraph">
|
|
<p>If you’ve ever wondered how after all the redirections, posts,
|
|
etc. involved in Web-SSO one finally returns back to the original
|
|
requested resource, you will find the answer in SAML’s <code>RelayState</code>
|
|
parameter. The <code>RelayState</code> is set by the SP when it first initiates
|
|
authentication. SAML requires every party that handles a SAML message
|
|
to preserve the <code>RelayState</code> and ultimately return it to the original
|
|
requester. Officially SAML constrains the <code>RelayState</code> to a maximum of
|
|
80 bytes and recommends it be integrity protected and not expose
|
|
sensitive information because it often appears in the URL of SAML
|
|
messages. This could be achieved by pairing the URL with a random
|
|
string, using the random string as the <code>RelayState</code>, and then obtaining the
|
|
original URL by performing a look-up. However in practice most SAML
|
|
clients set the <code>RelayState</code> to the resource URL. This is what Mellon
|
|
currently does.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When you are examining SAML messages, the <code>RelayState</code> will be the
|
|
original URL and depending on the SAML binding it may be
|
|
URL-encoded. <em>Just be aware that there is no requirement the <code>RelayState</code> be
|
|
the original URL. It can be any string that the client can use
|
|
to establish the context.</em> At some future date Mellon may alter its
|
|
<code>RelayState</code> handling.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="metadata">4.13. The Role of Metadata</h3>
|
|
<div class="paragraph">
|
|
<p>When a SAML provider needs to interact with another SAML provider they
|
|
must know various properties of the foreign provider (i.e. its
|
|
configuration). SAML provider properties are encapsulated in an XML
|
|
document called SAML metadata. Examples of the provider properties
|
|
conveyed in metadata include:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#entityID">entityID</a> (the unique name of the provider)</p>
|
|
</li>
|
|
<li>
|
|
<p>Organizational information</p>
|
|
</li>
|
|
<li>
|
|
<p>The roles this provider offers (e.g. SP, IdP, etc.)</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#endpoints">endpoints</a> for message exchange</p>
|
|
</li>
|
|
<li>
|
|
<p>X509 certificates the provider uses and for what purpose</p>
|
|
</li>
|
|
<li>
|
|
<p>Should messages be signed</p>
|
|
</li>
|
|
<li>
|
|
<p>Attributes and attribute profiles</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Typically at start-up a provider loads its own metadata (to configure
|
|
itself) and then loads the metadata of all providers it interacts
|
|
with.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The SAML metadata specification can be found here:
|
|
<a href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf" class="bare">https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf</a></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>It is vital that SAML metadata be trusted. The SAML specifications do not
|
|
prescribe how metadata is exchanged in a trusted fashion. Many
|
|
providers offer a URL where their metadata can be downloaded from (see
|
|
<a href="#mellon_endpoints">Mellon Endpoints</a>). Metadata can be signed by the
|
|
provider, which establishes authenticity. Some SAML practitioners do
|
|
not approve of downloading metadata and instead insist upon the
|
|
private exchange of metadata as a means to assure the metadata is
|
|
valid, thus providing a higher level of trust.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>Practical field experience has demonstrated that the vast majority of SAML
|
|
problems are due to invalid metadata. Therefore the ability to
|
|
diagnose SAML problems demands the ability to read and understand SAML
|
|
metadata.</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To that end let’s explore the provider metadata used in our examples.</p>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="metadata_keys">4.13.1. Certs and Keys Inside Metadata</h4>
|
|
<div class="paragraph">
|
|
<p>Cryptographic keys are used in SAML to sign pieces of data providing
|
|
integrity protection and to encrypt data to provide
|
|
confidentiality. In order for two SAML providers to successfully
|
|
exchange SAML messages between themselves they must know the public
|
|
keys of the other party. The provider’s public keys are declared in
|
|
its metadata and are always encapsulated inside a
|
|
<code><md:KeyDescriptor></code> element that defines its intended use (signing
|
|
or encryption). Furthermore one or more of the following
|
|
representations within a <code><ds:KeyInfo></code> element <strong>MUST</strong> be present:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code><ds:KeyValue></code></p>
|
|
</li>
|
|
<li>
|
|
<p><code><ds:X509Certificate></code> (child element of <code><ds:X509Data></code>)</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><em>The (common) use of a <code><ds:X509Certificate></code> element is merely a
|
|
notational convenience to encapsulate a key. SAML never utilizes any
|
|
PKI information inside an X509 certificate; the only data SAML
|
|
utilizes from an X509 certificate is the key material.</em> This has
|
|
several implications:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Certs are never PKI validated.</p>
|
|
</li>
|
|
<li>
|
|
<p>Certification extensions that define key usage, etc. are never
|
|
checked.</p>
|
|
</li>
|
|
<li>
|
|
<p>The certificate validity period is never checked, thus a cert
|
|
contained in metadata never expires as a consequence of its
|
|
certificate validity period. Instead the validity period of the
|
|
<strong>key</strong> is controlled by the <code><md:validUntil></code> or <code><md:cacheDuration></code>
|
|
metadata attribute associated with the key.</p>
|
|
</li>
|
|
<li>
|
|
<p>Using self-signed certs used in SAML metadata is fine because the
|
|
PKI data is never evaluated.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>In fact extracting the key from an <code><ds:X509Certificate></code> element and
|
|
placing it inside a <code><ds:KeyValue></code> element instead is semantically
|
|
identical. A <code><ds:X509Certificate></code> element is just a container for the
|
|
key, nothing more than that. Certificates are used only because they
|
|
are easy to generate and are readily available.</p>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
The consequence of the above is that a provider’s metadata <strong>is</strong>
|
|
the trust mechanism in SAML. <strong><em>Any compromise of a provider’s metadata
|
|
is a compromise of SAML security.</em></strong>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
Even though the keys and certs used inside SAML metadata
|
|
for signing and encryption are not PKI validated, the key and cert used
|
|
to establish a TLS secure channel between SAML entities <strong>MUST</strong> be
|
|
fully PKI validated using a chain all the way up to a trusted CA. Do not
|
|
confuse the purpose of the keys and certs used for the purpose of
|
|
signing and encrypting SAML data with those used to establish secure
|
|
communication: they are entirely distinct.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="sp_metadata">4.13.2. Service Provider Metadata</h4>
|
|
<div class="paragraph">
|
|
<p>This is an example of Mellon metadata. It is the SP metadata used in
|
|
our example authentication.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<EntityDescriptor <i class="conum" data-value="1"></i><b>(1)</b>
|
|
xmlns="urn:oasis:names:tc:SAML:2.0:metadata" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
xmlns:ds="http://www.w3.org/2000/09/xmldsig#" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
entityID="https://mellon.example.com/mellon/metadata"> <i class="conum" data-value="3"></i><b>(3)</b>
|
|
<SPSSODescriptor <i class="conum" data-value="4"></i><b>(4)</b>
|
|
AuthnRequestsSigned="true" <i class="conum" data-value="5"></i><b>(5)</b>
|
|
WantAssertionsSigned="true" <i class="conum" data-value="6"></i><b>(6)</b>
|
|
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
|
<KeyDescriptor use="signing"> <i class="conum" data-value="7"></i><b>(7)</b>
|
|
<ds:KeyInfo>
|
|
<ds:X509Data>
|
|
<ds:X509Certificate>...</ds:X509Certificate>
|
|
</ds:X509Data>
|
|
</ds:KeyInfo>
|
|
</KeyDescriptor>
|
|
<KeyDescriptor use="encryption"> <i class="conum" data-value="8"></i><b>(8)</b>
|
|
<ds:KeyInfo>
|
|
<ds:X509Data>
|
|
<ds:X509Certificate>...</ds:X509Certificate>
|
|
</ds:X509Data>
|
|
</ds:KeyInfo>
|
|
</KeyDescriptor>
|
|
<SingleLogoutService <i class="conum" data-value="9"></i><b>(9)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
|
|
Location="https://mellon.example.com/mellon/logout" />
|
|
<SingleLogoutService <i class="conum" data-value="10"></i><b>(10)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
|
Location="https://mellon.example.com/mellon/logout" />
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> <i class="conum" data-value="11"></i><b>(11)</b>
|
|
<AssertionConsumerService <i class="conum" data-value="12"></i><b>(12)</b>
|
|
index="0"
|
|
isDefault="true" <i class="conum" data-value="13"></i><b>(13)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
|
Location="https://mellon.example.com/mellon/postResponse" />
|
|
<AssertionConsumerService <i class="conum" data-value="14"></i><b>(14)</b>
|
|
index="1"
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
|
|
Location="https://mellon.example.com/mellon/artifactResponse" />
|
|
<AssertionConsumerService <i class="conum" data-value="15"></i><b>(15)</b>
|
|
index="2"
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
|
|
Location="https://mellon.example.com/mellon/paosResponse" />
|
|
</SPSSODescriptor>
|
|
</EntityDescriptor></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>EntityDescriptor</code> is a container for all properties belonging to
|
|
the entity identified by the <code>entityID</code> name. SAML metadata allows
|
|
a single metadata document to describe multiple entities. In that case
|
|
the top level element will be a <code><EntitiesDescriptor></code> element which
|
|
will contain one or more <code><EntityDescriptor></code> elements. If the
|
|
metadata describes only a single entity, it is permissible to just use
|
|
a <code><EntityDescriptor></code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>XML namespace declaration. This provides an abbreviated shorthand
|
|
to identify which namespace an XML element belongs to. The shorthand
|
|
name is the string preceding the equals sign. If the name is absent it
|
|
becomes the default namespace for XML elements which are not prefixed
|
|
with a namespace. Thus for example <code>xmlns:ds="…​"</code> sets <code>ds</code> as
|
|
the namespace prefix for XML digital signature elements and
|
|
<code><ds:KeyInfo></code> means the <code>KenInfo</code> element belongs to the XML digital
|
|
signature namespace because it is prefixed with <code>ds:</code>. <strong>There is no
|
|
prescribed list of namespace prefixes, rather the document defines the
|
|
prefix.</strong> By convention certain prefix names are commonly used. <em>A
|
|
common mistake is to assume that all SAML XML documents will use the same
|
|
namespace prefixes</em>. This is not true and leads to misunderstandings
|
|
and/or parsing errors.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td><a id="sp_metadata_entityid"></a> entityID. This is the unique name of the SAML provider. It <strong>must</strong>
|
|
be a URI. See <a href="#entityID">entityID</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td>A provider role. In this instance the role is <code>SPSSODescriptor</code>,
|
|
which means it’s a Service Provider. A provider may have multiple
|
|
roles, therefore an entity may have more than one role element. In our
|
|
example there is only one role. See <a href="#saml_roles">SAML Roles</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td><code>AuthnRequestsSigned</code>. If true then the SP will be sending a signed
|
|
<code><AuthnRequest></code> to the IdP.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td><code>WantAssertionsSigned</code>. If true then the SP desires the IdP to
|
|
sign its assertions. Assertions should always be signed.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="7"></i><b>7</b></td>
|
|
<td>X509 certificate information. The <code>use</code> attribute of <code>signing</code>
|
|
identifies that this certificate will be used for signing data.
|
|
There may be multiple keys of this type, permitting key rotation.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="8"></i><b>8</b></td>
|
|
<td>X509 certificate information. The <code>use</code> attribute of <code>encryption</code>
|
|
identifies that this certificate will be used for encrypting data.
|
|
There may be multiple keys of this type, permitting key rotation.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="9"></i><b>9</b></td>
|
|
<td>SAML endpoint. Logout messages using a SOAP binding are sent to
|
|
this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="10"></i><b>10</b></td>
|
|
<td>SAML endpoint. Logout messages using the HTTP-Redirect binding
|
|
are sent to this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="11"></i><b>11</b></td>
|
|
<td>Zero or more <code><NameIDFormat></code> elements enumerate the name
|
|
identifier formats supported by this entity. See <a href="#name_id">Username, userid, SAML NameID</a> for
|
|
details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="12"></i><b>12</b></td>
|
|
<td><a id="sp_metadata_acs"></a> SAML endpoint. Assertions using the HTTP-POST binding are
|
|
delivered to this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="13"></i><b>13</b></td>
|
|
<td>For indexed endpoints if <code>isDefault</code> is true then this is the
|
|
default endpoint to select. If no endpoint claims to be the default
|
|
then the first endpoint in the list is the default.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="14"></i><b>14</b></td>
|
|
<td>SAML endpoint. Assertions using the HTTP-Artifact binding are
|
|
delivered to this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="15"></i><b>15</b></td>
|
|
<td>SAML endpoint. Assertions using the PAOS binding are delivered to
|
|
this URL location. PAOS is used the the Enhanced Client or Proxy
|
|
Profile (a.k.a. ECP).</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="idp_metadata">4.13.3. Identity Provider Metadata</h4>
|
|
<div class="paragraph">
|
|
<p>This is an example of a IdP metadata as generated by a Red Hat SSO
|
|
server (Keycloak). It is the IdP metadata used in our example
|
|
authentication.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><?xml version="1.0" encoding="UTF-8"?>
|
|
<EntitiesDescriptor Name="urn:keycloak" <i class="conum" data-value="1"></i><b>(1)</b>
|
|
xmlns="urn:oasis:names:tc:SAML:2.0:metadata" <i class="conum" data-value="2"></i><b>(2)</b>
|
|
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> <i class="conum" data-value="2"></i><b>(2)</b>
|
|
<EntityDescriptor <i class="conum" data-value="3"></i><b>(3)</b>
|
|
entityID="https://rhsso.example.com:8443/auth/realms/test"> <i class="conum" data-value="4"></i><b>(4)</b>
|
|
<IDPSSODescriptor <i class="conum" data-value="5"></i><b>(5)</b>
|
|
WantAuthnRequestsSigned="true" <i class="conum" data-value="6"></i><b>(6)</b>
|
|
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
|
<KeyDescriptor use="signing"> <i class="conum" data-value="7"></i><b>(7)</b>
|
|
<dsig:KeyInfo>
|
|
<dsig:KeyName>1VPndjfABB6S4lb4zwMLjBUhxfzPFnfrvNYvRgcxiUM</dsig:KeyName>
|
|
<dsig:X509Data>
|
|
<dsig:X509Certificate>...</dsig:X509Certificate>
|
|
</dsig:X509Data>
|
|
</dsig:KeyInfo>
|
|
</KeyDescriptor>
|
|
<SingleLogoutService <i class="conum" data-value="8"></i><b>(8)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
|
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
|
|
<SingleLogoutService <i class="conum" data-value="9"></i><b>(9)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
|
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> <i class="conum" data-value="10"></i><b>(10)</b>
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> <i class="conum" data-value="10"></i><b>(10)</b>
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat> <i class="conum" data-value="10"></i><b>(10)</b>
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat> <i class="conum" data-value="10"></i><b>(10)</b>
|
|
<SingleSignOnService <i class="conum" data-value="11"></i><b>(11)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
|
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
|
|
<SingleSignOnService <i class="conum" data-value="12"></i><b>(12)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
|
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
|
|
<SingleSignOnService <i class="conum" data-value="13"></i><b>(13)</b>
|
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
|
|
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
|
|
</IDPSSODescriptor>
|
|
</EntityDescriptor>
|
|
</EntitiesDescriptor></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>EntitiesDescriptor</code> is a container for multiple
|
|
<code><EntityDesciptor></code> elements.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>XML namespace declaration. This provides an abbreviated shorthand
|
|
to identify which namespace an XML element belongs to. The shorthand
|
|
name is the string preceding the equals sign. If the name is absent it
|
|
becomes the default namespace for XML elements which are not prefixed
|
|
with a namespace. Thus for example <code>xmlns:ds="…​"</code> sets <code>ds</code> as
|
|
the namespace prefix for XML digital signature elements and
|
|
<code><ds:KeyInfo></code> means the <code>KeyInfo</code> element belongs to the XML digital
|
|
signature namespace because it is prefixed with <code>ds:</code>. <strong>There is no
|
|
prescribed list of namespace prefixes, rather the document defines the
|
|
prefix.</strong> By convention certain prefix names are commonly used. <em>A
|
|
common mistake is to assume all SAML XML documents will use the same
|
|
namespace prefixes</em>. This is not true and leads to misunderstandings
|
|
and/or parsing errors.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td><code>EntityDescriptor</code> is a container for all properties belonging to
|
|
the entity identified by the <code>entityID</code> name.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td>entityID. This is the unique name of the SAML provider. It <strong>must</strong>
|
|
be a URI. See <a href="#entityID">entityID</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td>A provider role. In this instance the role is <code>IDPSSODescriptor</code>,
|
|
which means it’s an Identity Provider. A provider may have multiple
|
|
roles, therefore an entity may have more than one role element. In our
|
|
example there is only one role. See <a href="#saml_roles">SAML Roles</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td><code>WantAuthnRequestsSigned</code>. If true, indicates that this IdP requires
|
|
every <code><AuthnRequest></code> submitted by an SP to be signed.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="7"></i><b>7</b></td>
|
|
<td>X509 certificate information. The <code>use</code> attribute of <code>signing</code>
|
|
identifies that this certificate will be used for signing data.
|
|
There may be multiple keys of this type, permitting key rotation.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="8"></i><b>8</b></td>
|
|
<td>SAML endpoint. Logout messages using the HTTP-POST binding are
|
|
sent to this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="9"></i><b>9</b></td>
|
|
<td>SAML endpoint. Logout messages using the HTTP-Redirect binding are
|
|
sent to this URL location.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="10"></i><b>10</b></td>
|
|
<td>Zero or more <code><NameIDFormat></code> elements enumerate the name
|
|
identifier formats supported by this entity. See <a href="#name_id">Username, userid, SAML NameID</a> for more
|
|
details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="11"></i><b>11</b></td>
|
|
<td>SAML endpoint. <code><AuthnRequest></code> messages using the HTTP-POST
|
|
binding are sent by the SP to this URL location to establish a Single
|
|
Sign-On Session.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="12"></i><b>12</b></td>
|
|
<td>SAML endpoint. <code><AuthnRequest></code> messages using the HTTP-Redirect
|
|
binding are sent by the SP to this URL location to establish a Single
|
|
Sign-On Session.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="13"></i><b>13</b></td>
|
|
<td>SAML endpoint. <code><AuthnRequest></code> messages using the SOAP
|
|
binding are sent by the SP to this URL location to establish a Single
|
|
Sign-On Session.</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_installing_configuring_mellon">5. Installing & Configuring Mellon</h2>
|
|
<div class="sectionbody">
|
|
<div class="sect2">
|
|
<h3 id="_installing_mellon">5.1. Installing Mellon</h3>
|
|
<div class="paragraph">
|
|
<p>Mellon can be built and installed from source code located in the
|
|
<a href="https://github.com/UNINETT/mod_auth_mellon">mod_auth_mellon GitHub
|
|
repository</a>. However for most people the best option is to install
|
|
Mellon using a pre-built package available from the package manager on
|
|
your operating system. Pre-built packages relieve you of having to
|
|
know the intricacies of building and installing from source, track and
|
|
install security fixes, and track and apply bug fixes. Pre-built
|
|
packages also are tailored to your operating system environment, often
|
|
including OS specific configuration and support files deemed useful by
|
|
the packaging authority.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="title">On RHEL (CentOS)</div>
|
|
<div class="content">
|
|
<pre>sudo yum install mod_auth_mellon</pre>
|
|
</div>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="title">On Fedora</div>
|
|
<div class="content">
|
|
<pre>sudo dnf install mod_auth_mellon</pre>
|
|
</div>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="title">On Debian (Ubuntu)</div>
|
|
<div class="content">
|
|
<pre>apt-get install libapache2-mod-auth-mellon</pre>
|
|
</div>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="title">From source</div>
|
|
<div class="content">
|
|
<pre>./configure
|
|
make
|
|
sudo make install</pre>
|
|
</div>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
If building from source you’ll need to have all the necessary
|
|
dependencies available at build time. Determining the exact set of
|
|
dependencies and where to locate them is operating system
|
|
dependent. It is assumed you have the necessary knowledge to correctly
|
|
perform the requisite operations which is out of scope for this document.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_config">5.2. Mellon Configuration</h3>
|
|
<div class="paragraph">
|
|
<p>Once installed, mod_auth_mellon does not do anything until it’s
|
|
configured to operate on a URL. Mellon is configured in the same way
|
|
as other Apache modules. See
|
|
<a href="http://httpd.apache.org/docs/current/configuring.html">Apache
|
|
Configuration Files</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>There are two independent steps necessary to enable Mellon.</p>
|
|
</div>
|
|
<div class="olist arabic">
|
|
<ol class="arabic">
|
|
<li>
|
|
<p>Load the mod_auth_mellon Apache module at Apache start-up.</p>
|
|
</li>
|
|
<li>
|
|
<p>Configure Mellon to operate on specific URLs with specific SAML
|
|
properties.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="load_mod_auth_mellon">5.2.1. Load mod_auth_mellon</h4>
|
|
<div class="paragraph">
|
|
<p>To accomplish the first task of loading the mod_auth_mellon module
|
|
Apache needs to execute this configuration directive:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre>LoadModule auth_mellon_module modules/mod_auth_mellon.so</pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Different distributions may handle Apache module loading differently, but as
|
|
of Apache 2.4 the preferred technique is to drop a file in the
|
|
<code>conf.modules.d</code> Apache directory with the above content. Apache
|
|
automatically processes all <code>.conf</code> files in this directory at
|
|
start-up.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
<div class="title">Red Hat Specific</div>
|
|
<div class="paragraph">
|
|
<p>Red Hat RPM’s add the file
|
|
<code>/etc/httpd/conf.modules.d/10-auth_mellon.conf</code> with the above
|
|
<code>LoadModule</code> directive, so there is no further action needed to load
|
|
the module after the RPM is installed.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="mellon_config_files">5.2.2. Mellon Configuration Files</h4>
|
|
<div class="paragraph">
|
|
<p>To accomplish the second task of configuring Mellon, Apache will need
|
|
to read Mellon configuration directives when it initializes. The
|
|
preferred mechanism is to place those directives in a file located in
|
|
the Apache <code>conf.d</code> directory, Apache will read all <code>.conf</code> files in
|
|
this directory at start-up. Although you could place the Mellon
|
|
directives in any config file, a good practice to follow is keep the
|
|
Mellon directives in their own file. See <a href="#mellon_config_file">Mellon Configuration File</a> for
|
|
more information.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon relies on SAML specific files as well, for example:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>IdP metadata file(s)</p>
|
|
</li>
|
|
<li>
|
|
<p>Mellon’s SP metadata file</p>
|
|
</li>
|
|
<li>
|
|
<p>Certificate and key files</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Although you are free to locate these SAML specific files in the
|
|
<code>/etc/httpd/conf.d</code> Apache configuration directory, they are not
|
|
strictly speaking Apache configuration files. Many deployments choose
|
|
to locate the SAML files in a sibling directory, for example
|
|
<code>/etc/httpd/saml2</code>.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
If you are running with SELinux enabled (as you should be) you
|
|
may run into SELinux file permission problems if you locate files
|
|
Mellon reads and writes outside the standard Apache directories
|
|
because externally located files will not automatically receive the
|
|
proper SELinux labels.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_mellon_configuration_directives">5.3. Mellon Configuration Directives</h3>
|
|
<div class="paragraph">
|
|
<p>Mellon’s configuration directives are documented in Mellon’s <code>README</code>
|
|
file. The README is the best place to learn and review Mellon
|
|
configuration directives because it will match the installed version
|
|
of Mellon.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
<div class="title">Red Hat Specific</div>
|
|
<div class="paragraph">
|
|
<p>Red Hat RPM’s install the README file in
|
|
<code>/usr/share/doc/mod_auth_mellon*/README</code>.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon configuration directives are broken into 2 types:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Module level (i.e. global values shared by each virtual server)</p>
|
|
</li>
|
|
<li>
|
|
<p>Directory level (i.e. applied to directories and URL locations)</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The README groups all module level directives together at the top of
|
|
the file, the directory level directory level directives follow. Most
|
|
users will only need to configure the directory level directives which
|
|
comprise 2 basic types and are documented in <a href="http://httpd.apache.org/docs/current/mod/core.html">Apache Core Features</a>:</p>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1"><Directory> Directive</dt>
|
|
<dd>
|
|
<p>Enclose a group of directives that apply only
|
|
to the named file-system directory, sub-directories, and their
|
|
contents.</p>
|
|
</dd>
|
|
<dt class="hdlist1"><Location> Directive</dt>
|
|
<dd>
|
|
<p>Applies the enclosed directives only to
|
|
matching URLs.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The critical thing to remember when writing and reading Mellon
|
|
configuration is that like all Apache directory level configuration it is
|
|
<strong><em>hierarchical</em></strong>. The path portion of the URL is like a file system
|
|
directory tree. If a Mellon configuration directive is not
|
|
<em>explicitly</em> defined for a particular point in the tree, the value is
|
|
<strong><em>inherited</em></strong> from the closest ancestor that defines it. If no
|
|
ancestor defines the value then Mellon’s default value is applied. The
|
|
default value for each Mellon configuration directive is listed in
|
|
Mellon’s <code>README</code> file.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_config_file">5.4. Mellon Configuration File</h3>
|
|
<div class="paragraph">
|
|
<p>For our demo example we will place these directives in the file
|
|
<code>/etc/httpd/conf.d/demo_mellon.conf</code>. Let’s briefly review what the
|
|
demo configuration is meant to accomplish and illustrate:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>We are protecting with SAML authentication the URL location
|
|
<code><a href="https://mellon.example.com/private" class="bare">https://mellon.example.com/private</a></code> and everything below it in URL
|
|
space.</p>
|
|
</li>
|
|
<li>
|
|
<p>To eliminate redundant cut-n-paste of shared SAML directives in each
|
|
protected location we gather the common Mellon directives in a
|
|
location <em>above</em> any of the protected locations in the URL
|
|
tree. This permits all protected locations to hierarchically inherit
|
|
the same values from a common single set of directives.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre><Location /> <i class="conum" data-value="1"></i><b>(1)</b>
|
|
MellonEnable info <i class="conum" data-value="2"></i><b>(2)</b>
|
|
MellonEndpointPath /mellon/ <i class="conum" data-value="3"></i><b>(3)</b>
|
|
MellonSPMetadataFile /etc/httpd/saml2/demo_sp_metadata.xml <i class="conum" data-value="4"></i><b>(4)</b>
|
|
MellonSPPrivateKeyFile /etc/httpd/saml2/demo.key <i class="conum" data-value="5"></i><b>(5)</b>
|
|
MellonSPCertFile /etc/httpd/saml2/demo.cert <i class="conum" data-value="6"></i><b>(6)</b>
|
|
MellonIdPMetadataFile /etc/httpd/saml2/demo_keycloak_test_idp_metadata.xml <i class="conum" data-value="7"></i><b>(7)</b>
|
|
</Location>
|
|
|
|
<Location /private> <i class="conum" data-value="8"></i><b>(8)</b>
|
|
AuthType Mellon <i class="conum" data-value="9"></i><b>(9)</b>
|
|
MellonEnable auth <i class="conum" data-value="10"></i><b>(10)</b>
|
|
Require valid-user <i class="conum" data-value="11"></i><b>(11)</b>
|
|
</Location></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td>The first <code>Location</code> directive on the <code>/</code> <em>root</em> is simply a
|
|
convenient place to locate common configuration directives that will
|
|
be shared by all Mellon protected locations. In this instance it
|
|
defines the metadata files and certificates and keys. It is not
|
|
necessary to locate this on the <code>/</code> <em>root</em> URL, in fact in a real
|
|
world deployment you probably will want to locate the common shared
|
|
set of Mellon directives lower in the hierarchy. The only requirement
|
|
is that <em>all</em> of the protected locations are positioned below it so they may
|
|
inherit those values. <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>Mellon does not process any directives unless it’s enabled for
|
|
that location either explicitly or via inheritance. See
|
|
<a href="#mellon_modes">Mellon Modes</a> for more details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td>Defines where the Mellon endpoints are located in URL space. This
|
|
is a <strong>critical</strong> value to properly specify and is one of the <strong><em>most
|
|
common Mellon configuration errors</em></strong> leading to a failed deployment.
|
|
Please refer to <a href="#mellon_endpoint_path">MellonEndpointPath</a> to
|
|
understand its requirements and what it influences. Also see
|
|
<a href="#incorrect_mellon_endpoint_path">Incorrect MellonEndpointPath</a> for a discussion of this common
|
|
error. The important thing to note in this example is the
|
|
<code>MellonEndpointPath</code> is located <strong>inside</strong> the containing location
|
|
directive of <code>/</code> (e.g. a child).</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td>The SAML metadata for this provider (i.e. Mellon’s metadata). This
|
|
metadata plays 2 important roles: Mellon reads it at start-up to
|
|
initialize itself, and you provide the IdP specified in
|
|
<code>MellonIdPMetadataFile</code> with this metadata. Both Mellon (the SP) and
|
|
your IdP <strong>MUST</strong> have loaded exactly the same Mellon metadata in other
|
|
to interoperate. Out of sync metadata is a very common deployment
|
|
error. See <a href="#metadata_creation">Metadata Creation</a> for how Mellon
|
|
metadata is created. <code>MellonSPMetadataFile</code> is optional, Mellon can
|
|
create its own metadata from its initial configuration parameters.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td>The private cryptographic key used by Mellon to sign its SAML
|
|
data. See <a href="#metadata_keys">Certs and Keys Inside Metadata</a> for more detail.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td>The public cryptographic key associated with the private key. This
|
|
public key is embedded in Mellon’s metadata so that an IdP can
|
|
validate Mellon’s signed data. See <a href="#metadata_keys">Certs and Keys Inside Metadata</a> for more detail.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="7"></i><b>7</b></td>
|
|
<td>The IdP used to authenticate is specified by its metadata
|
|
file. See <a href="#obtain_idp_metadata">Obtaining IdP Metadata</a> for how to obtain this data.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="8"></i><b>8</b></td>
|
|
<td>This is a URL location protected by Mellon. For our example we’ve
|
|
used the <code>/private</code> URL. Note that this <code><Location></code> block is simple and
|
|
does not contain many of the necessary Mellon directives, because those other
|
|
Mellon directives are inherited from an ancestor location, in our
|
|
example <code>/</code>. The only Mellon directives in this location block are
|
|
those necessary to turn on Mellon authentication. This configuration
|
|
strategy permits you to define many subordinate protected locations all
|
|
sharing the same common Mellon directives via inheritance.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="9"></i><b>9</b></td>
|
|
<td><code>AuthType</code> is an Apache directive specifying which Apache
|
|
authentication module will perform the authentication for this
|
|
location. Obviously we want to use Mellon.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="10"></i><b>10</b></td>
|
|
<td>Instruct Mellon that this location (and all its descendants) will be
|
|
authenticated. See <a href="#mellon_modes">Mellon Modes</a>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="11"></i><b>11</b></td>
|
|
<td><code>Require</code> is an Apache directive that instructs Apache’s
|
|
authentication and authorization sub-system that it must successfully
|
|
authenticate the user.</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="load_sp_metadata_into_idp">5.4.1. Load Your SP metadata into the IdP</h4>
|
|
<div class="paragraph">
|
|
<p>After you have created your SP metadata as described in
|
|
<a href="#metadata_creation">Metadata Creation</a>, you must load your metadata
|
|
into the IdP referenced in your <code>MellonIdPMetadataFile</code>. How to
|
|
perform the SP metadata load is specific to the IdP you’re using and
|
|
you will need to consult your IdP documentation to learn the procedure.</p>
|
|
</div>
|
|
<div class="admonitionblock warning">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-warning" title="Warning"></i>
|
|
</td>
|
|
<td class="content">
|
|
If you subsequently modify your SP metadata you <strong>MUST</strong> reload
|
|
it into the IdP. Both your metadata and the IdP metadata must be in
|
|
sync at all times. Failure to reload any modified metadata is a recipe
|
|
for problems.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="obtain_idp_metadata">5.4.2. Obtaining IdP Metadata</h4>
|
|
<div class="paragraph">
|
|
<p>In order to Mellon to communicate with and interoperate with an IdP it
|
|
must have the IdP’s metadata. You may want to refer to <a href="#metadata">The Role of Metadata</a> for
|
|
a more comprehensive description. But how do you obtain the metadata
|
|
belonging to the IdP? There is no fixed rule on how this is
|
|
accomplished. You will have to refer to your IdP’s documentation. It
|
|
may be published at a well known location (e.g. a URL) for download or
|
|
there may be some other publication mechanism.</p>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
SAML provider metadata is extremely security sensitive, it
|
|
contains the cryptographic keys used to secure SAML. If you download
|
|
metadata from a URL do so only over a secure channel such as https and
|
|
make sure the download operation properly validates the server cert up
|
|
to a CA you trust. <em>Do not trust a server offering a self-signed
|
|
cert</em>. If the obtained metadata is signed you <strong>MUST</strong> validate the
|
|
signature on the metadata.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_modes">5.5. Mellon Modes</h3>
|
|
<div class="paragraph">
|
|
<p>For any given location Mellon can be in one of 3 modes defined by the
|
|
<code>MellonEnable</code> directive:</p>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">off</dt>
|
|
<dd>
|
|
<p>Mellon will not do anything in this location.
|
|
This is the default state.</p>
|
|
</dd>
|
|
<dt class="hdlist1">info</dt>
|
|
<dd>
|
|
<p>If the user is authorized to access the resource, then
|
|
Mellon will populate the environment with information about
|
|
the user. If the user isn’t authorized, then Mellon won’t
|
|
populate the environment, but Mellon won’t deny the user
|
|
access either.</p>
|
|
</dd>
|
|
<dt class="hdlist1">auth</dt>
|
|
<dd>
|
|
<p>Mellon will populate the environment with information about
|
|
the user if he is authorized. If he is authenticated
|
|
(logged in), but not authorized (according to the
|
|
<code>MellonRequire</code> and <code>MellonCond</code> directives, then Mellon will
|
|
return a 403 Forbidden error. If he isn’t authenticated
|
|
then Mellon will redirect to the login page of the configured IdP.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The most common situation is to protect a specific location with
|
|
Mellon authentication. This requires at a minimum these 3 directives:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre> AuthType Mellon <i class="conum" data-value="1"></i><b>(1)</b>
|
|
MellonEnable auth <i class="conum" data-value="2"></i><b>(2)</b>
|
|
Require valid-user <i class="conum" data-value="3"></i><b>(3)</b></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td>This is an Apache directive that says authentication is to be
|
|
performed with Mellon as opposed to another Apache authentication
|
|
module.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>This informs Mellon it is to perform authentication as described
|
|
above.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td>This is an Apache directive that says an authentication module
|
|
must have successfully authenticated a user in order to proceed.</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="metadata_creation">5.6. How is Mellon metadata created?</h3>
|
|
<div class="paragraph">
|
|
<p>The purpose of SAML metadata is describe in <a href="#metadata">The Role of Metadata</a>. An annotated
|
|
example of Mellon metadata is presented in <a href="#sp_metadata">Service Provider Metadata</a>. There are
|
|
multiple ways one can create Mellon metadata:</p>
|
|
</div>
|
|
<div class="olist arabic">
|
|
<ol class="arabic">
|
|
<li>
|
|
<p>Use the <code>mellon_create_metadata.sh</code> script. The mod_auth_mellon RPM
|
|
installs this script in
|
|
<code>/usr/libexec/mod_auth_mellon/mellon_create_metadata.sh</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Allow Mellon to dynamically generate its metadata based on its
|
|
configuration options. The metadata can be downloaded from the
|
|
<code>$MellonEndpointPath/metadata</code> URL. Mellon only self-generates its
|
|
metadata if the <code>MellonSPMetadataFile</code> configuration parameter is not
|
|
defined, otherwise if the <code>MellonSPMetadataFile</code> is defined the
|
|
<code>$MellonEndpointPath/metadata</code> download URL will return the contents
|
|
of the <code>MellonSPMetadataFile</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Use a third-party tool such as <code>keycloak-http-client-install</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Write it from scratch. (Not kidding, many provider administrators
|
|
hand create and hand edit their metadata).</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
Before proceeding further with Mellon metadata it is
|
|
essential you understand the <a href="#mellon_endpoint_path">MellonEndpointPath</a>.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="using_mellon_create_metadata_sh">5.6.1. Using <code>mellon_create_metadata.sh</code></h4>
|
|
<div class="paragraph">
|
|
<p><code>mellon_create_metadata.sh</code> requires two positional parameters</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#entityID">entityID</a></p>
|
|
</li>
|
|
<li>
|
|
<p>endpoint_url</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The entityID is the unique name of the Mellon SP. The entityID plays
|
|
an important role in SAML and you may wish to review its description
|
|
in <a href="#entityID">entityID</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The endpoint_url is the concatenation of the <code>https</code> scheme, the Mellon
|
|
hostname, and the <a href="#mellon_endpoint_path">MellonEndpointPath</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Using our example data the entityID will be
|
|
<code><a href="https://mellon.example.com/mellon/metadata" class="bare">https://mellon.example.com/mellon/metadata</a></code> and the endpoint_url will
|
|
be <code><a href="https://mellon.example.com/mellon" class="bare">https://mellon.example.com/mellon</a></code></p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre>$ /usr/libexec/mod_auth_mellon/mellon_create_metadata.sh "https://mellon.example.com/mellon/metadata" "https://mellon.example.com/mellon"
|
|
Output files:
|
|
Private key: https_mellon.example.com_mellon_metadata.key
|
|
Certificate: https_mellon.example.com_mellon_metadata.cert
|
|
Metadata: https_mellon.example.com_mellon_metadata.xml
|
|
Host: mellon.example.com
|
|
|
|
Endpoints:
|
|
SingleLogoutService (SOAP): https://mellon.example.com/mellon/logout
|
|
SingleLogoutService (HTTP-Redirect): https://mellon.example.com/mellon/logout
|
|
AssertionConsumerService (HTTP-POST): https://mellon.example.com/mellon/postResponse
|
|
AssertionConsumerService (HTTP-Artifact): https://mellon.example.com/mellon/artifactResponse
|
|
AssertionConsumerService (PAOS): https://mellon.example.com/mellon/paosResponse</pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The script produces 3 files containing the cert, key, and metadata, all
|
|
prefixed with the entityID. In this example it would be:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>https_mellon.example.com_mellon_metadata.cert</p>
|
|
</li>
|
|
<li>
|
|
<p>https_mellon.example.com_mellon_metadata.key</p>
|
|
</li>
|
|
<li>
|
|
<p>https_mellon.example.com_mellon_metadata.xml</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You will need to move these files into the Apache configuration
|
|
directory and possibly rename them to something more sensible. You will refer to
|
|
these files inside the Mellon
|
|
configuration as these Mellon directives:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>MellonSPPrivateKeyFile</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MellonSPCertFile</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MellonSPMetadataFile</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="using_mellon_to_create_metadata">5.6.2. Using Mellon to generate its own metadata</h4>
|
|
<div class="paragraph">
|
|
<p>Mellon has the built-in capability to generate its own metadata as
|
|
long as you provide a few necessary Mellon configuration directives.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>MellonSPentityId</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MellonSPPrivateKeyFile</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MellonSPCertFile</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MellonEndpointPath</code> (not mandatory if you use the default)</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When Mellon initializes it will check the value of the
|
|
<code>MellonSPMetadataFile</code>. If it does not exist Mellon will generate
|
|
its own metadata. If <code>MellonSPMetadataFile</code> exists, that metadata will
|
|
always be used. If Mellon generates its own metadata it does not
|
|
write the metadata back to a file, rather it’s held in memory.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Irrespective of whether Mellon self generates its metadata or if it
|
|
loads it from a file specified by <code>MellonSPMetadataFile</code>, the metadata
|
|
is made available for download at the <code>$MellonEndpointPath/metadata</code>
|
|
URL. You can perform a GET on this URL to capture the SP metadata and
|
|
save it in a file. It is recommended you do this as an initial
|
|
configuration set-up step and then always subsequently load the
|
|
metadata via the <code>MellonSPMetadataFile</code> directive. The rationale for
|
|
this is you want to be sure you know what metadata Mellon is
|
|
initializing with and that it identically matches what you’ve loaded
|
|
into the IdP. You may also wish to customize your SP metadata by
|
|
making edits to it.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_where_do_the_keys_and_certs_come_from">5.6.3. Where do the keys and certs come from?</h4>
|
|
<div class="paragraph">
|
|
<p>Please refer to the <a href="#metadata_keys">Certs and Keys Inside Metadata</a> section to understand how keys
|
|
and certs are utilized inside SAML (TLS connections used for SAML
|
|
communication is an entirely different matter and it is mandated keys
|
|
and certs used for TLS be PKI validated). The main point to
|
|
understand is that even though most SAML implementations use x509 utilities
|
|
to generate certs and keys, SAML’s use of them does not involve PKI.
|
|
Only the key material is used. The consequence of this is it’s
|
|
okay to generate self-signed certs for use inside a provider’s metadata
|
|
because they are not PKI validated. Many of the metadata creation
|
|
tools generate a self-signed cert for use in the metadata. However it
|
|
is perfectly fine to use your own key and cert instead of one
|
|
generated by an installation tool. You can accomplish this with Mellon
|
|
by pointing the <code>MellonSPPrivateKeyFile</code> and <code>MellonSPCertFile</code>
|
|
directives at your own key and cert files and then downloading the SP
|
|
metadata as described in <a href="#using_mellon_to_create_metadata">Using Mellon to generate its own metadata</a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="sign_metadata">5.6.4. Signing metadata</h4>
|
|
<div class="paragraph">
|
|
<p>SAML requires provider metadata to be integrity protected. Publishing
|
|
provider metadata over a secure TLS channel goes a long way to
|
|
accomplishing this goal and may be considered sufficient depending on
|
|
the security requirements. SAML metadata can be integrity protected by
|
|
signing the metadata with an XML signature. Some providers may require
|
|
any metadata they consume be signed. Unfortunately neither Mellon nor
|
|
any of the tools currently associated with Mellon have support for
|
|
signing Mellon metadata. Fortunately there are a variety of tools
|
|
available to sign an XML document and since SAML metadata is a normal
|
|
XML document any of these tools can be used to sign the Mellon
|
|
metadata.</p>
|
|
</div>
|
|
<div class="sect4">
|
|
<h5 id="xmlsec_metadata_signing">Using xmlsec to sign metadata</h5>
|
|
<div class="paragraph">
|
|
<p>The <code>xmlsec</code> tools are commonly available on most Linux based
|
|
system. In fact the <code>Lasso</code> library which supplies Mellon with its
|
|
SAML implementation uses the <code>xmlsec</code> library to perform all of its
|
|
XML signing and signature verification. <code>xmlsec</code> usually ships with an
|
|
<code>xmlsec</code> command line utility, which can perform XML signing
|
|
and verification from the command line.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
<code>xmlsec</code> may be packaged under the name <code>xmlsec1</code> in your
|
|
distribution. This is the case for all Red Hat distributions.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To sign Mellon metadata using <code>xmlsec</code> you need to add a signature
|
|
template to the Mellon metadata. When <code>xmlsec</code> reads the input
|
|
metadata it locates the empty signature template and replaces it with
|
|
a processed signature. The signature template should be placed near
|
|
the top of the metadata, ideally just after the <code><EntityDescriptor></code>
|
|
element. Here is an example of a signature template:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlight"><code class="language-xml" data-lang="xml"><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
<SignedInfo>
|
|
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n"/>
|
|
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
<Reference URI="">
|
|
<Transforms>
|
|
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
|
</Transforms>
|
|
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
<DigestValue></DigestValue>
|
|
</Reference>
|
|
</SignedInfo>
|
|
<SignatureValue />
|
|
<KeyInfo>
|
|
<KeyValue />
|
|
</KeyInfo>
|
|
</Signature></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Because the <code><Reference> URI</code> attribute is the empty string the entire
|
|
document will be signed. In order for <code>xmlsec</code> to generate a signature
|
|
you will need to supply it with both the private and public key parts.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre>xmlsec \\ <i class="conum" data-value="1"></i><b>(1)</b>
|
|
--sign \\ <i class="conum" data-value="2"></i><b>(2)</b>
|
|
--privkey-pem demo.key \\ <i class="conum" data-value="3"></i><b>(3)</b>
|
|
--pubkey-cert-pem demo.cert \\ <i class="conum" data-value="4"></i><b>(4)</b>
|
|
--output signed_metadata.xml \\ <i class="conum" data-value="5"></i><b>(5)</b>
|
|
metadata.xml <i class="conum" data-value="6"></i><b>(6)</b></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>xmlsec</code> command may be named <code>xmlsec1</code> on your system</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>Perform signing</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td>Private key used for signing</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
|
<td>Public key used to verify signature (included in signature)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
|
<td>Output file containing signed metadata</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="6"></i><b>6</b></td>
|
|
<td>Input unsigned metadata (with signature template)</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To verify the signature on the command line:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre>xmlsec \\ <i class="conum" data-value="1"></i><b>(1)</b>
|
|
--verify \\ <i class="conum" data-value="2"></i><b>(2)</b>
|
|
signed_metadata.xml <i class="conum" data-value="3"></i><b>(3)</b></pre>
|
|
</div>
|
|
</div>
|
|
<div class="colist arabic">
|
|
<table>
|
|
<tr>
|
|
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
|
<td><code>xmlsec</code> command may be named <code>xmlsec1</code> on your system</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
|
<td>Perform verification</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
|
<td>Input signed metadata</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_endpoint_path">5.7. MellonEndpointPath</h3>
|
|
<div class="paragraph">
|
|
<p>Mellon reserves a number of URLs for its use. Some of these
|
|
URLs are the public SAML <a href="#endpoints">endpoints</a> advertised in the
|
|
<a href="#sp_metadata">SP metadata</a>. Others are for Mellon’s private use.
|
|
The best way to think of these Mellon endpoints is as a way of binding a
|
|
URL to a handler. When an HTTP request arrives at one of these Mellon
|
|
endpoints a dedicated handler processes the request.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The way Mellon identifies a URL as being one of its endpoints is by
|
|
looking at the beginning of the URL path. If everything in the path
|
|
except the last path component matches the <code>MellonEndpointPath</code> then
|
|
Mellon recognizes the URL as being one of its endpoints. The last
|
|
path component is used to bind to the handler.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Let’s use an example. If the <code>MellonEndpointPath</code> is <code>/foo/bar</code> then
|
|
any URL with the form <code>/foo/bar/xxx</code> will be handled by Mellon’s xxx
|
|
handler.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon enforces 2 strict requirements on the <code>MellonEndpointPath</code>:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>The path <strong>must</strong> be an absolute path from the root of the web server.</p>
|
|
</li>
|
|
<li>
|
|
<p>The path <strong>must</strong> be a sub-path of the Mellon <code><Location></code>
|
|
directive that defines it. The reason for this is simple. Mellon
|
|
ignores locations which are not configured for Mellon. Therefore for
|
|
Mellon to respond to a request on one of its SAML endpoints, the
|
|
endpoint has to be inside a path that Mellon is watching.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_endpoints">5.8. Mellon Endpoints</h3>
|
|
<div class="paragraph">
|
|
<p>Mellon endpoints are hung off of the <a href="#mellon_endpoint_path">MellonEndpointPath</a>.
|
|
Mellon reserves a number of URLs for its use. Some of these
|
|
URLs are the public SAML <a href="#endpoints">endpoints</a> advertised in the
|
|
<a href="#sp_metadata">SP metadata</a>. Others are for Mellon’s private use.
|
|
The best way to think of these Mellon endpoints is a way of binding a
|
|
URL to a handler. When an HTTP request arrives at one of these Mellon
|
|
endpoints a dedicated handler processes the request.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The current list of Mellon endpoints (handlers) is:</p>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">postResponse</dt>
|
|
<dd>
|
|
<p>The <em>AssertionConsumerService</em> endpoint using the SAML HTTP-POST
|
|
binding.</p>
|
|
</dd>
|
|
<dt class="hdlist1">artifactResponse</dt>
|
|
<dd>
|
|
<p>The <em>AssertionConsumerService</em> endpoint for SAML artifacts. SAML artifacts
|
|
provide an indirect method to convey data. An artifact is an
|
|
identifier that points to data. Requesting data using the artifact
|
|
identifier returns the associated data.</p>
|
|
</dd>
|
|
<dt class="hdlist1">paosResponse</dt>
|
|
<dd>
|
|
<p>The AssertionConsumerService endpoint using the SAML PAOS
|
|
binding.</p>
|
|
</dd>
|
|
<dt class="hdlist1">login</dt>
|
|
<dd>
|
|
<p>Mellon internal endpoint used to start the authentication process with
|
|
an IdP. Any request whose URL needs authentication is redirected here
|
|
to start the login process.</p>
|
|
</dd>
|
|
<dt class="hdlist1">logout</dt>
|
|
<dd>
|
|
<p>The SingleLogoutService SAML endpoint.</p>
|
|
</dd>
|
|
<dt class="hdlist1">metadata</dt>
|
|
<dd>
|
|
<p>A HTTP GET request on this endpoint will return the SP’s metadata.</p>
|
|
</dd>
|
|
<dt class="hdlist1">repost</dt>
|
|
<dd>
|
|
<p>Mellon internal endpoint which replays POST data from the original
|
|
request.</p>
|
|
</dd>
|
|
<dt class="hdlist1">auth</dt>
|
|
<dd>
|
|
<p>Mellon internal endpoint retained for backwards compatibility.</p>
|
|
</dd>
|
|
<dt class="hdlist1">probeDisco</dt>
|
|
<dd>
|
|
<p>IdP probe discovery service endpoint. See "Probe IdP discover" in the
|
|
Mellon README for more information.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_session">5.9. Mellon Session</h3>
|
|
<div class="paragraph">
|
|
<p>SAML sessions are described in <a href="#saml_sessions">Sessions</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>For each successfully authenticated user Mellon maintains a
|
|
session. Mellon allocates a unique ID for the session when it is
|
|
created. The Mellon session ID is sent to the user’s browser in a
|
|
<a href="#mellon_cookie">Mellon Cookie</a>. The <a href="#mellon_cookie">Mellon Cookie</a> is sent back to Mellon in
|
|
every request the browser makes to the SP. Mellon uses the session ID
|
|
to look-up the session data for the user. Internally Mellon calls
|
|
session data <em>cache data</em> (this is subject to change).</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>At the time of this writing Mellon session data is local to one Apache
|
|
server (which may have multiple worker processes sharing data in
|
|
shared memory). This has consequences for High Availability (e.g. HA)
|
|
deployments which may be running multiple Apache servers on different
|
|
nodes behind a load balancer, see <a href="#load_balancer_persistence">Load balancer proxy persistence</a> for
|
|
detailed information on this issue.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon limits the duration of a valid session by the length of time
|
|
defined in the <code>MellonSessionLength</code> directive. Currently the default
|
|
is 86400 seconds which is 24 hours.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The IdP can inform the SP how long it wishes a SP session to be valid
|
|
by passing the <code>SessionNotOnOrAfter</code> attribute in a
|
|
<code><AuthnStatement></code>. Mellon respects the <code>SessionNotOnOrAfter</code>
|
|
attribute and will limit its session duration based on it. Thus the
|
|
validity period for a Mellon session is the lesser of the
|
|
<code>MellonSessionLength</code> or the optional IdP <code>SessionNotOnOrAfter</code>
|
|
attribute if the IdP supplied it.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="mellon_cookie">5.10. Mellon Cookie</h3>
|
|
<div class="paragraph">
|
|
<p><a href="#mellon_session">Mellon Session</a> information is communicated via a cookie. The
|
|
cookie name defaults to <code>mellon-cookie</code> but may be changed via the
|
|
Mellon directive <code>MellonVariable</code>. Mellon always forms the cookie name
|
|
by appending the value of <code>MellonVariable</code> to the string <code>mellon-</code> to
|
|
prevent name collisions. Thus the actual default value of
|
|
<code>MellonVariable</code> is <code>cookie</code>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When Mellon first begins the authentication process it sets the mellon
|
|
cookie value to <code>cookietest</code>. The primary purpose of the <code>cookietest</code>
|
|
value is to confirm cookies are properly returned by the browser,
|
|
Mellon will not work correctly unless cookies are enabled. The
|
|
<code>cookietest</code> value also serves as a temporary value
|
|
indicating an authentication flow is in progress but has not yet
|
|
completed.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>After Mellon successfully authenticates a user it establishes a
|
|
session for the user and generates a unique session ID which it sets
|
|
as the value of the Mellon cookie. When Mellon receives a request for
|
|
a protected resource it looks for the Mellon cookie in the HTTP
|
|
request headers. Mellon then uses the Mellon cookie value as a session
|
|
ID and attempts to look-up that session using that ID. If the session
|
|
is found and it remains valid, Mellon immediately grants access. A
|
|
Mellon session will expire, see <a href="#mellon_session">Mellon Session</a> for information
|
|
concerning session lifetime.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_working_with_saml_attributes_and_exporting_values_to_web_apps">6. Working with SAML attributes and exporting values to web apps</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>When you receive a SAML assertion authenticating a subject, the
|
|
assertion will likely include additional attributes provided by the
|
|
IdP concerning the subject. Examples include the user’s email address
|
|
or the groups they are a member of. You may wish to review the
|
|
<a href="#assertion_response">assertion example</a> and look for
|
|
<code><saml:Attribute></code> and <code><saml:AttributeValue></code> elements to see how the
|
|
IdP communicates these attributes. There is no fixed set of attributes
|
|
returned by an IdP, it is entirely IdP dependent. You will either have
|
|
to review your IdP’s documentation or examine a returned assertion to
|
|
determine the possible attributes. See <a href="#inspect_saml_messages">Inspect SAML messages</a> for the
|
|
various ways you can examine the contents of a returned assertion.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Mellon communicates its results via Apache environment variables. For
|
|
every attribute received in the assertion Mellon will insert an Apache
|
|
environment variable. You have some flexibility on how Mellon adds
|
|
these environment variables which derive from the assertion
|
|
attributes.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Attributes can be multi-valued. <code>MellonMergeEnvVars</code> controls
|
|
whether each value is added to the environment by appending an index
|
|
to the attribute name or whether the values are listed together
|
|
under the bare attribute name with each value separated by a
|
|
separator character. See <a href="#multiple_attribute_values">Handling multiple attribute values</a>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Attribute names can be mapped from the name as it appears in the
|
|
assertion to a name of your choosing when it is placed in the Apache
|
|
environment. This is controlled by <code>MellonSetEnv</code> and
|
|
<code>MellonSetEnvNoPrefix</code> directives. The distinction
|
|
is <code>MellonSetEnv</code> always prepends the <code>MELLON_</code> prefix to the
|
|
environment variable name to help to prevent name collisions. The
|
|
<code>MellonSetEnvNoPrefix</code> directive also remaps the assertion name to a
|
|
name of your choosing but it omits prepending the environment
|
|
variable name with <code>MELLON_</code>. See <a href="#map_assertion_attr_name">Map assertion attribute name to different Apache environment variable name</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Using the <a href="#assertion_response">assertion example</a> Mellon places these
|
|
environment variables in the Apache environment. See
|
|
<a href="#multiple_attribute_values">Handling multiple attribute values</a> for an explanation of
|
|
<code>MellonMergeEnvVars</code> and its effect.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="title">MellonMergeEnvVars Off</div>
|
|
<div class="content">
|
|
<pre>MELLON_NAME_ID: G-803528aa-2f9e-454b-a89c-55ee74e75d1e
|
|
MELLON_NAME_ID_0: G-803528aa-2f9e-454b-a89c-55ee74e75d1e
|
|
MELLON_groups: ipausers
|
|
MELLON_groups_0: ipausers
|
|
MELLON_groups_1: openstack-users
|
|
MELLON_email: jdoe@music.com
|
|
MELLON_email_0: jdoe@music.com
|
|
MELLON_display_name: John Doe
|