commit
051a8e4331
After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,53 @@ |
||||
Publik |
||||
======= |
||||
|
||||
|image0| |
||||
|
||||
Presentation |
||||
------------ |
||||
|
||||
Publik is an open-source citizen relationship management tool. |
||||
|
||||
See `the official Publik website <https://publik.entrouvert.com/>`__ for a |
||||
complete presentation. |
||||
|
||||
It feature an OpenID Connect login that work with LemonLDAP::NG. |
||||
|
||||
Configuring Publik |
||||
------------------- |
||||
|
||||
Connect to your publik instance authentic2 webui with an Admin user, in the admin panel, go to "Authentic2_Auth_Oidc" › "Oidc providers". |
||||
|
||||
Click on "Add Oidc Provider". |
||||
|
||||
* Name : LemonLDAP SSO |
||||
* Short id : lemonldap |
||||
* Provider : https://auth.example.com/ |
||||
* Client id : clientid |
||||
* Client secret : secret |
||||
* Authorization endpoint : https://auth.example.com/oauth2/authorize |
||||
* Token endpoint : https://auth.example.com/oauth2/token |
||||
* Userinfo endpoint : https://auth.example.com/oauth2/userinfo |
||||
* End session endpont : https://auth.example.com/oauth2/logout |
||||
* WebKey JSON : Copy/Paste the content of https://auth.example.com/oauth2/jwks |
||||
* Claims Enabled : yes |
||||
* Show on connection page : yes |
||||
|
||||
Strategy and Collectivity can be configured based to your needs. |
||||
|
||||
OIDC Claim mappings can be configured based on your needs. |
||||
|
||||
Configuring LemonLDAP |
||||
~~~~~~~~~~~~~~~~~~~~~ |
||||
|
||||
We now have to configure LemonLDAP::NG to recognize publik as a valid OIDC relying party. |
||||
|
||||
Add a :doc:`new OpenID Connect relying party<..//idpopenidconnect>` |
||||
with the following parameters (Options -> Basic) : |
||||
|
||||
* **Client ID**: the same you set in Publik configuration. |
||||
* **Client Secret**: the same you set in Publik configuration. |
||||
* **Allowed redirection addresses for login**: The "Callback URL" for authentic2 : https://authentic2-instance/accounts/oidc/callback/ |
||||
|
||||
.. |image0| image:: /applications/logo-publik.png |
||||
:class: align-center |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@ |
||||
!function(){var o=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){if(console.log("Error",t),(e=JSON.parse(e.responseText))&&e.error)return e=e.error.replace(/.* /,""),console.log("Returned error",e),o(e,"warning")},t="",e=function(e){return o("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),o(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?o("yourNewTotpKey","warning"):o("yourTotpKey","success"),t=e.token):o("PE24","danger")}})},n=function(){var e=$("#code").val();return e?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?o(e.error,"warning"):o(e.error,"danger"):o("yourKeyIsRegistered","success")}}):o("fillTheForm","warning")};$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",n)})}.call(this); |
||||
(function(){var r,e,n,t,o;n=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),n(o,"warning")},t="",e=function(e){return n("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),n(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?n("yourNewTotpKey","warning"):n("yourTotpKey","success"),t=e.token):n("PE24","danger")}})},o=function(){var e;return(e=$("#code").val())?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?n(e.error,"warning"):n(e.error,"danger"):n("yourKeyIsRegistered","success")}}):n("fillTheForm","warning")},$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",function(){return o()})})}).call(this); |
@ -1 +1 @@ |
||||
{"version":3,"sources":["totpregistration.js"],"names":["setMsg","msg","level","$","html","window","translate","removeClass","addClass","displayError","j","status","err","console","log","res","JSON","parse","responseText","error","replace","token","getKey","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","verify","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCO,EAAe,SAASC,EAAGC,EAAQC,GAIjC,GAFAC,QAAQC,IAAI,QAASF,IACrBG,EAAMC,KAAKC,MAAMP,EAAEQ,gBACRH,EAAII,MAGb,OAFAJ,EAAMA,EAAII,MAAMC,QAAQ,MAAO,IAC/BP,QAAQC,IAAI,iBAAkBC,GACvBf,EAAOe,EAAK,YAIvBM,EAAQ,GAERC,EAAS,SAASC,GAEhB,OADAvB,EAAO,cAAe,WACfG,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVJ,MAAOV,EACPsB,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKV,OACHU,EAAKV,MAAMc,MAAM,oBACnB9B,EAAE,cAAc+B,OAEXlC,EAAO6B,EAAKV,MAAO,YAEtBU,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvCjC,EAAE,cAAckC,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAER3C,EAAE,eAAe4C,KAAKf,GAClBH,EAAKC,OACP9B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBqB,EAAQQ,EAAKR,OArBXrB,EAAO,OAAQ,cA0B9BgD,EAAS,WACP,IACAC,EAAM9C,EAAE,SAAS8C,MACjB,OAAKA,EAGI9C,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJR,MAAOA,EACP6B,KAAMD,EACNE,SAAUhD,EAAE,aAAa8C,OAE3B9B,MAAOV,EACPsB,QAAS,SAASF,GAChB,OAAIA,EAAKV,MACHU,EAAKV,MAAMc,MAAM,kBACZjC,EAAO6B,EAAKV,MAAO,WAEnBnB,EAAO6B,EAAKV,MAAO,UAGrBnB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCG,EAAEwC,UAAUS,MAAM,WAKhB,OAJA9B,EAAO,GACPnB,EAAE,cAAckD,GAAG,QAAS,WAC1B,OAAO/B,EAAO,KAETnB,EAAE,WAAWkD,GAAG,QACdL,MAIVM,KAAKC"} |
||||
{"version":3,"sources":["totpregistration.js"],"names":["displayError","getKey","setMsg","token","verify","msg","level","$","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAAIA,EAAcC,EAAQC,EAAQC,EAAOC,EAEzCF,EAAS,SAASG,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCN,EAAe,SAASa,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBd,EAAOc,EAAK,YAIvBb,EAAQ,GAERF,EAAS,SAASuB,GAEhB,OADAtB,EAAO,cAAe,WACfK,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVF,MAAOtB,EACPgC,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKR,OACHQ,EAAKR,MAAMY,MAAM,oBACnB3B,EAAE,cAAc4B,OAEXjC,EAAO4B,EAAKR,MAAO,YAEtBQ,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvC9B,EAAE,cAAc+B,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAERxC,EAAE,eAAeyC,KAAKf,GAClBH,EAAKC,OACP7B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBC,EAAQ2B,EAAK3B,OArBXD,EAAO,OAAQ,cA0B9BE,EAAS,WACP,IAAI6C,EAEJ,OADAA,EAAM1C,EAAE,SAAS0C,OAIR1C,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJ3B,MAAOA,EACP+C,KAAMD,EACNE,SAAU5C,EAAE,aAAa0C,OAE3B3B,MAAOtB,EACPgC,QAAS,SAASF,GAChB,OAAIA,EAAKR,MACHQ,EAAKR,MAAMY,MAAM,kBACZhC,EAAO4B,EAAKR,MAAO,WAEnBpB,EAAO4B,EAAKR,MAAO,UAGrBpB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCK,EAAEqC,UAAUQ,MAAM,WAKhB,OAJAnD,EAAO,GACPM,EAAE,cAAc8C,GAAG,QAAS,WAC1B,OAAOpD,EAAO,KAETM,EAAE,WAAW8C,GAAG,QAAS,WAC9B,OAAOjD,UAIVkD,KAAKC"} |
@ -0,0 +1,345 @@ |
||||
use lib 'inc'; |
||||
use Test::More; |
||||
use strict; |
||||
use IO::String; |
||||
use LWP::UserAgent; |
||||
use LWP::Protocol::PSGI; |
||||
use MIME::Base64; |
||||
|
||||
BEGIN { |
||||
require 't/test-lib.pm'; |
||||
require 't/saml-lib.pm'; |
||||
} |
||||
|
||||
my $debug = 'error'; |
||||
my ( $issuer, $sp, $res ); |
||||
|
||||
# Redefine LWP methods for tests |
||||
LWP::Protocol::PSGI->register( |
||||
sub { |
||||
my $req = Plack::Request->new(@_); |
||||
fail('POST should not launch SOAP requests'); |
||||
count(1); |
||||
return [ 500, [], [] ]; |
||||
} |
||||
); |
||||
|
||||
sub runTest { |
||||
my ( $req_nif, $res_nif, $force_attr, $expect_req_nif, $expect_res_nif, |
||||
$expect_nameid ) |
||||
= @_; |
||||
|
||||
# Initialization |
||||
$issuer = register( 'issuer', sub { issuer( $res_nif, $force_attr ) } ); |
||||
$sp = register( 'sp', sub { sp($req_nif) } ); |
||||
|
||||
# Simple SP access |
||||
my $res; |
||||
ok( |
||||
$res = $sp->_get( |
||||
'/', accept => 'text/html', |
||||
), |
||||
'Unauth SP request' |
||||
); |
||||
count(1); |
||||
|
||||
expectOK($res); |
||||
my ( $host, $url, $s ) = |
||||
expectAutoPost( $res, 'auth.idp.com', '/saml/singleSignOn', |
||||
'SAMLRequest' ); |
||||
|
||||
my $sr = expectSamlRequest($s); |
||||
expectXPath( |
||||
$sr, '/samlp:AuthnRequest/samlp:NameIDPolicy/@Format', |
||||
$expect_req_nif, 'Found expected NameID Format in request', |
||||
); |
||||
|
||||
# Push SAML request to IdP |
||||
ok( |
||||
$res = $issuer->_post( |
||||
$url, |
||||
IO::String->new($s), |
||||
accept => 'text/html', |
||||
length => length($s) |
||||
), |
||||
'Post SAML request to IdP' |
||||
); |
||||
count(1); |
||||
expectOK($res); |
||||
my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); |
||||
|
||||
# Try to authenticate with an authorized user to IdP |
||||
$s = "user=french&password=french&$s"; |
||||
ok( |
||||
$res = $issuer->_post( |
||||
$url, |
||||
IO::String->new($s), |
||||
accept => 'text/html', |
||||
cookie => $pdata, |
||||
length => length($s), |
||||
), |
||||
'Post authentication' |
||||
); |
||||
count(1); |
||||
my $idpId = expectCookie($res); |
||||
|
||||
# Expect pdata to be cleared |
||||
$pdata = expectCookie( $res, 'lemonldappdata' ); |
||||
ok( $pdata !~ 'issuerRequestsaml', 'SAML request cleared from pdata' ) |
||||
or explain( $pdata, 'not issuerRequestsaml' ); |
||||
count(1); |
||||
|
||||
( $host, $url, $s ) = |
||||
expectAutoPost( $res, 'auth.sp.com', '/saml/proxySingleSignOnPost', |
||||
'SAMLResponse' ); |
||||
|
||||
my ($sr) = expectSamlResponse($s); |
||||
expectXPath( |
||||
$sr, '/samlp:Response/saml:Assertion/saml:Subject/saml:NameID/@Format', |
||||
$expect_res_nif, 'Found expected NameID Format in response', |
||||
); |
||||
|
||||
if ($expect_nameid) { |
||||
my $nameidvalue = expectXPath( $sr, |
||||
'/samlp:Response/saml:Assertion/saml:Subject/saml:NameID/text()' ); |
||||
if ( ref($expect_nameid) eq "Regexp" ) { |
||||
like( $nameidvalue, $expect_nameid, "NameID matches" ); |
||||
} |
||||
else { |
||||
is( $nameidvalue, $expect_nameid, "NameID matches" ); |
||||
} |
||||
} |
||||
} |
||||
|
||||
SKIP: { |
||||
eval "use Lasso"; |
||||
if ($@) { |
||||
skip 'Lasso not found'; |
||||
} |
||||
|
||||
# Default settings use the email NIF |
||||
runTest( |
||||
# requested NameIDFormat (sp side) |
||||
undef, |
||||
|
||||
# returned NameIDFormat (idp side) |
||||
undef, |
||||
|
||||
# Name ID session key |
||||
undef, |
||||
|
||||
# Expected NameIDFormat in SAMLRequest |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
|
||||
# Expected NameIDFormat in SAMLResponse |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
|
||||
# Expected NameID value |
||||
'fa@badwolf.org' |
||||
); |
||||
|
||||
# Override session key |
||||
runTest( |
||||
undef, |
||||
undef, |
||||
"uid", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
'french' |
||||
); |
||||
|
||||
# Using email explicitely return the email |
||||
runTest( |
||||
"email", |
||||
"email", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
'fa@badwolf.org' |
||||
); |
||||
|
||||
# Changing the format on the IDP side has no effect if the client |
||||
# specifies a NIF |
||||
runTest( |
||||
"email", |
||||
"kerberos", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", |
||||
'fa@badwolf.org' |
||||
); |
||||
|
||||
# Using unspecified on the requesting side causes IDP settings to be honored |
||||
# specifies a NIF |
||||
runTest( |
||||
"unspecified", |
||||
"kerberos", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos", |
||||
'french' |
||||
); |
||||
|
||||
# Unspecified both ways + no forced key returns no value |
||||
runTest( |
||||
"unspecified", |
||||
"unspecified", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
undef, |
||||
); |
||||
|
||||
# Unspecified both ways returns forced key in unspecified format |
||||
runTest( |
||||
"unspecified", |
||||
"unspecified", |
||||
'mail', |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
'fa@badwolf.org', |
||||
); |
||||
|
||||
# persistent asked by SP returns a value |
||||
runTest( |
||||
"persistent", |
||||
"email", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", |
||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", |
||||
qr/./, |
||||
); |
||||
|
||||
# persistent chosen by IDP returns a value |
||||
runTest( |
||||
"unspecified", |
||||
"persistent", |
||||
undef, |
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", |
||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", |
||||
qr/./, |
||||
); |
||||
|
||||
} |
||||
|
||||
clean_sessions(); |
||||
done_testing(); |
||||
|
||||
sub issuer { |
||||
my ( $res_nif, $force_attr ) = @_; |
||||
return LLNG::Manager::Test->new( { |
||||
ini => { |
||||
logLevel => $debug, |
||||
domain => 'idp.com', |
||||
portal => 'http://auth.idp.com', |
||||
authentication => 'Demo', |
||||
userDB => 'Same', |
||||
issuerDBSAMLActivation => 1, |
||||
issuerDBSAMLRule => '$uid eq "french"', |
||||
samlSPMetaDataOptions => { |
||||
'sp.com' => { |
||||
samlSPMetaDataOptionsEncryptionMode => 'none', |
||||
samlSPMetaDataOptionsSignSSOMessage => 1, |
||||
samlSPMetaDataOptionsSignSLOMessage => 1, |
||||
samlSPMetaDataOptionsCheckSSOMessageSignature => 0, |
||||
samlSPMetaDataOptionsCheckSLOMessageSignature => 0, |
||||
( |
||||
$res_nif |
||||
? ( samlSPMetaDataOptionsNameIDFormat => $res_nif, ) |
||||
: () |
||||
), |
||||
( |
||||
$force_attr |
||||
? ( samlSPMetaDataOptionsNameIDSessionKey => |
||||
$force_attr, ) |
||||
: () |
||||
), |
||||
} |
||||
}, |
||||
samlSPMetaDataExportedAttributes => { |
||||
'sp.com' => { |
||||
cn => |
||||
'1;cn;urn:oasis:names:tc:SAML:2.0:attrname-format:basic', |
||||
uid => |
||||
'1;uid;urn:oasis:names:tc:SAML:2.0:attrname-format:basic', |
||||
} |
||||
}, |
||||
samlOrganizationDisplayName => "IDP", |
||||
samlOrganizationName => "IDP", |
||||
samlOrganizationURL => "http://www.idp.com/", |
||||
samlServicePrivateKeyEnc => saml_key_idp_private_enc, |
||||
samlServicePrivateKeySig => saml_key_idp_private_sig, |
||||
samlServicePublicKeyEnc => saml_key_idp_public_enc, |
||||
samlServicePublicKeySig => saml_key_idp_public_sig, |
||||
samlSPMetaDataXML => { |
||||
"sp.com" => { |
||||
samlSPMetaDataXML => |
||||
samlSPMetaDataXML( 'sp', 'HTTP-POST' ) |
||||
}, |
||||
}, |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
sub sp { |
||||
my ($req_nif) = @_; |
||||
return LLNG::Manager::Test->new( { |
||||
ini => { |
||||
logLevel => $debug, |
||||
domain => 'sp.com', |
||||
portal => 'http://auth.sp.com', |
||||
authentication => 'SAML', |
||||
userDB => 'Same', |
||||
issuerDBSAMLActivation => 0, |
||||
restSessionServer => 1, |
||||
samlIDPMetaDataExportedAttributes => { |
||||
idp => { |
||||
mail => "0;mail;;", |
||||
uid => "1;uid", |
||||
cn => "0;cn" |
||||
} |
||||
}, |
||||
samlIDPMetaDataOptions => { |
||||
idp => { |
||||
samlIDPMetaDataOptionsEncryptionMode => 'none', |
||||
samlIDPMetaDataOptionsSSOBinding => 'post', |
||||
samlIDPMetaDataOptionsSLOBinding => 'post', |
||||
samlIDPMetaDataOptionsSignSSOMessage => 1, |
||||
samlIDPMetaDataOptionsSignSLOMessage => 1, |
||||
samlIDPMetaDataOptionsCheckSSOMessageSignature => 1, |
||||
samlIDPMetaDataOptionsCheckSLOMessageSignature => 1, |
||||
samlIDPMetaDataOptionsForceUTF8 => 1, |
||||
samlIDPMetaDataOptionsSignSSOMessage => 0, |
||||
( |
||||
$req_nif |
||||
? ( samlIDPMetaDataOptionsNameIDFormat => $req_nif, |
||||
) |
||||
: () |
||||
), |
||||
} |
||||
}, |
||||
samlIDPMetaDataExportedAttributes => { |
||||
idp => { |
||||
"uid" => "0;uid;;", |
||||
"cn" => "1;cn;;", |
||||
}, |
||||
}, |
||||
samlIDPMetaDataXML => { |
||||
idp => { |
||||
samlIDPMetaDataXML => |
||||
samlIDPMetaDataXML( 'idp', 'HTTP-POST' ) |
||||
} |
||||
}, |
||||
samlOrganizationDisplayName => "SP", |
||||
samlOrganizationName => "SP", |
||||
samlOrganizationURL => "http://www.sp.com", |
||||
samlServicePublicKeySig => saml_key_sp_public_sig, |
||||
samlServicePrivateKeyEnc => saml_key_sp_private_enc, |
||||
samlServicePrivateKeySig => saml_key_sp_private_sig, |
||||
samlServicePublicKeyEnc => saml_key_sp_public_enc, |
||||
samlSPSSODescriptorAuthnRequestsSigned => 1, |
||||
}, |
||||
} |
||||
); |
||||
} |
@ -0,0 +1,120 @@ |
||||
use Test::More; |
||||
use strict; |
||||
use IO::String; |
||||
use Data::Dumper; |
||||
|
||||
require 't/test-lib.pm'; |
||||
require 't/smtp.pm'; |
||||
|
||||
use_ok('Lemonldap::NG::Common::FormEncode'); |
||||
count(1); |
||||
|
||||
my $client = LLNG::Manager::Test->new( { |
||||
ini => { |
||||
logLevel => 'debug', |
||||
mail2fActivation => '$uid eq "msmith"', |
||||
mail2fAuthnLevel => 3, |
||||
mail2fCodeRegex => '\d{4}', |
||||
authentication => 'Demo', |
||||
userDB => 'Same', |
||||
} |
||||
} |
||||
); |
||||
|
||||
# Login as dwho |
||||
ok( |
||||
my $res = $client->_post( |
||||
'/', |
||||
IO::String->new('user=dwho&password=dwho'), |
||||
length => 23, |
||||
accept => 'text/html', |
||||
), |
||||
'Auth query' |
||||
); |
||||
count(1); |
||||
my $dwho_id = expectCookie($res); |
||||
|
||||
ok( |
||||
$res = $client->_get( |
||||
'/', cookie => "lemonldap=$dwho_id", |
||||
), |
||||
'Get portal' |
||||
); |
||||
expectAuthenticatedAs($res, 'dwho'); |
||||
count(1); |
||||
|
||||
# Start logging in as msmith |
||||
my $s = buildForm({ |
||||
user => 'msmith', |
||||
password => 'msmith', |
||||
}); |
||||
ok( |
||||
$res = $client->_post( |
||||
'/', |
||||
IO::String->new($s), |
||||
length => length($s), |
||||
accept => 'text/html', |
||||
), |
||||
'Auth query' |
||||
); |
||||
count(1); |
||||
|
||||
my ( $host, $url, $query ) = |
||||
expectForm( $res, undef, '/mail2fcheck?skin=bootstrap', 'token', 'code' ); |
||||
|
||||
ok( |
||||
$res->[2]->[0] =~ |
||||
qr%<input name="code" value="" type="text" class="form-control" id="extcode" trplaceholder="code" autocomplete="off" />%, |
||||
'Found EXTCODE input' |
||||
) or print STDERR Dumper( $res->[2]->[0] ); |
||||
count(1); |
||||
|
||||
ok( mail() =~ m%<b>(\d{4})</b>%, 'Found 2F code in mail' ) |
||||
or print STDERR Dumper( mail() ); |
||||
|
||||
my $code = $1; |
||||
count(1); |
||||
|
||||
# Fill the handler cache with dwho session info |
||||
ok( |
||||
$res = $client->_get( |
||||
'/', cookie => "lemonldap=$dwho_id", |
||||
), |
||||
'Get portal' |
||||
); |
||||
count(1); |
||||
|
||||
# Finish logging in as msmith, |
||||
# this corrupts the dwho cache with msmith macros |
||||
$query =~ s/code=/code=${code}/; |
||||
ok( |
||||
$res = $client->_post( |
||||
'/mail2fcheck', |
||||
IO::String->new($query), |
||||
length => length($query), |
||||
accept => 'text/html', |
||||
), |
||||
'Post code' |
||||
); |
||||
count(1); |
||||
diag Dumper($res); |
||||
|
||||
# Reuse the corrupted cache |
||||
ok( |
||||
$res = $client->_get( |
||||
'/', cookie => "lemonldap=$dwho_id", |
||||
), |
||||
'Get portal' |
||||
); |
||||
count(1); |
||||
|
||||
|
||||
TODO: { |
||||
local $TODO = "Fix 2539"; |
||||
expectAuthenticatedAs($res, 'dwho'); |
||||
} |
||||
|
||||
clean_sessions(); |
||||
|
||||
done_testing( count() ); |
||||
|
Loading…
Reference in new issue