Skip to content

Commit 4bf230a

Browse files
committed
Add support for multiple IdPs to the SamlTest testapp
Makes testing against Multiple IdPs much simpler to setup and configure
1 parent 905f78a commit 4bf230a

File tree

9 files changed

+74
-28
lines changed

9 files changed

+74
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ xt/testapp/sign-certonly-dsa.pem
2121
xt/testapp/sign-nopw-cert-dsa.pem
2222
xt/testapp/sign-private-dsa.pem
2323
Release-*
24+
xt/testapp/IdPs/*/*

xt/testapp/IdPs/.keep

Whitespace-only changes.

xt/testapp/README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Access http://localhost:3000
3333

3434
### Run lighttpd to proxy https to the Saml2Test application
3535

36-
Many SAML2 Identity Providers will not allow the application (Service Provider) URL to be http and force you to specify https to use SAML2. lighttpd is used to listen on port 443 and use https protocol so that the Identity Provider can redirect or POST to a https site. lighttpd then proxies that communication to the Dancer application listening on port 3000.
36+
Many SAML2 Identity Providers will not allow the application (Service Provider) URL to be http and forces you to specify https to use SAML2. lighttpd is used to listen on port 443 and use https protocol so that the Identity Provider can redirect or POST to a https site. lighttpd then proxies that communication to the Dancer application listening on port 3000.
3737

3838
1. cd xt/testapp
3939
2. sudo lighttpd -D -f lighttpd.conf
@@ -42,11 +42,15 @@ Note that the command requires sudo to allow it to use the default https port of
4242

4343
TODO: maybe change it to use 8443
4444

45-
### Create your metadata.xml file
45+
### Create your metadata.xml and cacert.pem file
4646

47-
Download the metadata for you configured application from your Identity Provider and save it to:
47+
The testapp now supports a simplified automatic configuration for testing against multiple Identity Providers (IdPs).
4848

49-
xt/testapp/metadata.xml
49+
1. Simply create a directory in xt/testapp/IdPs for the name of the IdP (eg. google)
50+
2. Download the metadata from your IdP and save it as IdPs/google/metadata.xml
51+
3. Download the cacert.pem from the IdP and save it as IdPs/google/cacert.pem
52+
53+
The index page will automatically list each configured Identity Provider as a link to initiate login against that IdP.
5054

5155
### Run lighttpd to deliver metadata.xml
5256

@@ -55,7 +59,7 @@ Net::SAML2 requires access to a URL containing the metadata. The simplest metho
5559
1. cd xt/testapp
5660
2. lighttpd -D -f lighttpd-metadata.conf
5761

58-
The metadata has been configured to be available at: http://localhost:8880/metadata.xml.
62+
The metadata has been configured to be available at: http://localhost:8880/metadata.xml. The simplified IdP configuration will automatically access the metadata.xml at http://localhost:8880/IdPs/googlee/metadata.xml (if you followed the instructions above and created the google directory in xt/testapp/IdPs)
5963

6064
Note that the configuration attempts to only deliver a file named metadata.xml from the xt/testapp directory. There are no guarantees - this is a test application so verify your own security.
6165

xt/testapp/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ layout: "main"
22
#logger: "console"
33
appname: "Saml2Test"
44
charset: "UTF-8"
5-
5+
template: "template_toolkit"
66
idp: "http://localhost:8880/metadata.xml"
77
issuer: "https://netsaml2-testapp.local"
88
url: "https://netsaml2-testapp.local"

xt/testapp/lib/Saml2Test.pm

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,41 @@ Demo app to show use of Net::SAML2 as an SP.
1616
use Dancer ':syntax';
1717
use Net::SAML2;
1818
use MIME::Base64 qw/ decode_base64 /;
19+
use File::Slurper qw/ read_dir /;
1920

20-
our $VERSION = '0.1';
21+
our $VERSION = '0.2';
2122

2223
get '/' => sub {
23-
template 'index';
24+
if ( ! -x './IdPs' ) {
25+
return "<html><pre>You must have a xt/testapp/IdPs directory</pre></html>";
26+
}
27+
my @dirs = read_dir('./IdPs');
28+
my @idps;
29+
for my $dir (sort @dirs) {
30+
if ( $dir eq '.keep' ) { next ; }
31+
my %tempidp;
32+
$tempidp{'idp'} = $dir;
33+
if ( -f "./IdPs/$dir/cacert.pem" ) {
34+
$tempidp{'cacert'} = 'exists';
35+
} else {
36+
$tempidp{'cacert'} = 'missing';
37+
}
38+
if ( -f "./IdPs/$dir/metadata.xml" ) {
39+
$tempidp{'metadata'} = 'exists';
40+
} else {
41+
$tempidp{'metadata'} = 'missing';
42+
}
43+
push @idps, \%tempidp;
44+
}
45+
46+
template 'index', { 'idps' => \@idps };
2447
};
2548

2649
get '/login' => sub {
50+
my $tokens = shift;
51+
52+
config->{cacert} = 'IdPs/' . params->{idp} . '/cacert.pem';
53+
config->{idp} = 'http://localhost:8880/IdPs/' . params->{idp} . '/metadata.xml';
2754
my $idp = _idp();
2855
my $sp = _sp();
2956
my $authnreq = $sp->authn_request(
@@ -86,7 +113,7 @@ get '/logout-soap' => sub {
86113
cert => 'sign-nopw-cert.pem',
87114
url => $slo_url,
88115
idp_cert => $idp_cert,
89-
cacert => 'saml_cacert.pem',
116+
cacert => config->{cacert},
90117
);
91118

92119
my $res = $soap->request($logoutreq);
@@ -97,7 +124,7 @@ get '/logout-soap' => sub {
97124

98125
post '/consumer-post' => sub {
99126
my $post = Net::SAML2::Binding::POST->new(
100-
cacert => 'saml_cacert.pem',
127+
cacert => config->{cacert},
101128
);
102129
my $ret = $post->handle_response(
103130
params->{SAMLResponse}
@@ -226,7 +253,7 @@ sub _sp {
226253
sub _idp {
227254
my $idp = Net::SAML2::IdP->new_from_url(
228255
url => config->{idp},
229-
cacert => 'saml_cacert.pem',
256+
cacert => config->{cacert},
230257
sls_force_lcase_url_encoding => config->{sls_force_lcase_url_encoding},
231258
sls_double_encoded_response => config->{sls_double_encoded_response}
232259
);

xt/testapp/lighttpd-metadata.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ $HTTP["host"] != "localhost" {
2424

2525
$HTTP["host"] == "localhost" {
2626

27-
$HTTP["url"] !~ "^/metadata.xml" {
27+
$HTTP["url"] !~ "metadata.xml" {
2828
url.access-deny = ("")
2929
}
3030
url.access-deny = ("disable")

xt/testapp/t/002_index_route.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use Dancer::Test;
88

99
route_exists [GET => '/'], 'a route handler is defined for /';
1010
response_status_is ['GET' => '/'], 200, 'response status is 200 for /';
11-
response_content_like [GET => '/'], qr/Log In/s,
11+
response_content_like [GET => '/'], qr/Login with/s,
1212
'content looks OK for /';
1313

1414
done_testing;

xt/testapp/views/index.tt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1-
<p><a href="/metadata.xml">SP Metadata</a></p>
1+
<% if idps.size >= 1 %>
2+
<h2>Login with:</h2>
3+
<ul>
4+
<% FOREACH provider IN idps %>
5+
<li><h3><a href ="/login?idp=<% provider.idp %>"><% provider.idp %> </a>
6+
<% if provider.metadata == 'missing' %>metadata missing <% end %>
7+
<% if provider.cacert == 'missing' %>cacert missing<% end %>
8+
</h3>
9+
<% END %>
10+
</ul>
11+
<% else %>
12+
<h2>No Identity Providers (IdP) found!</h2>
13+
<h3>Configure an Idp</h3>
14+
<ol>
15+
<li>Simply create a directory in xt/testapp/IdPs for the name of the IdP (eg. <i>google</i>)
16+
<li>Download the metadata from your IdP and save it to IdPs/<i>google</i>/metadata.xml
17+
<li>Download the cacert.pem from the IdP and save it to IdPs/<i>google</i>/cacert.pem
18+
</ol>
19+
<% end %>
20+
21+
<h2>Download SP <a href="/metadata.xml">Metadata</a></h2>
222

3-
<p><a href="/login">Log In</a></p>

xt/testapp/views/user.tt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1>User: <% assertion.nameid %></h1>
1+
<h1>NameID: <% assertion.nameid %></h1>
22

33
<p><a href="/logout-redirect?nameid=<% assertion.nameid | html %>&session=<% assertion.session | html %>">Logout (redirect binding)</a></p>
44

@@ -17,25 +17,21 @@
1717
<td>Issuer</td>
1818
<td><% assertion.issuer %></td>
1919
</tr>
20-
<tr>
21-
<td>DN</td>
22-
<td><% assertion.attributes.DN %></td>
23-
</tr>
24-
<tr>
25-
<td>CN</td>
26-
<td><% assertion.attributes.CN %></td>
27-
</tr>
2820
<tr>
2921
<td>EmailAddress</td>
30-
<td><% assertion.attributes.EmailAddress %></td>
22+
<td><% assertion.attributes.EmailAddress.0 %></td>
3123
</tr>
3224
<tr>
3325
<td>FirstName</td>
34-
<td><% assertion.attributes.FirstName %></td>
26+
<td><% assertion.attributes.FirstName.0 %><% assertion.attributes.fname.0 %></td>
27+
</tr>
28+
<tr>
29+
<td>LastName</td>
30+
<td><% assertion.attributes.LastName.0 %><% assertion.attributes.lname.0 %></td>
3531
</tr>
3632
<tr>
3733
<td>Address</td>
38-
<td><% assertion.attributes.Address %></td>
34+
<td><% assertion.attributes.Address.0 %></td>
3935
</tr>
4036
<tr>
4137
<td>Phone</td>
@@ -45,5 +41,4 @@
4541
<td>EmployeeNumber</td>
4642
<td><% assertion.attributes.EmployeeNumber %></td>
4743
</tr>
48-
<% end %>
4944
</table>

0 commit comments

Comments
 (0)