Skip to content

Commit 13c18ee

Browse files
authored
Merge pull request #56 from timlegge/testapp-multiple-idp-support
Testapp multiple idp support
2 parents 905f78a + a2ff662 commit 13c18ee

File tree

10 files changed

+110
-36
lines changed

10 files changed

+110
-36
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: 24 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,30 @@ 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+
### Configure the testapp to connect to the Identity Provider
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+
4. Optionally create IdPs/google/config.yml for custom settings for the IdP (if the a custom config.yml does not exist it will refresh the settings from the default config.yml.
53+
54+
The index page will automatically list each configured Identity Provider as a link to initiate login against that IdP.
55+
56+
Your directory structure should look like:
57+
58+
IdPs/
59+
auth0/
60+
cacert.pem
61+
metadata.yml
62+
azure/
63+
cacert.pem
64+
config.yml (optional)
65+
metadata.yml
66+
google/
67+
cacert.pem
68+
metadata.yml
5069

5170
### Run lighttpd to deliver metadata.xml
5271

@@ -55,7 +74,7 @@ Net::SAML2 requires access to a URL containing the metadata. The simplest metho
5574
1. cd xt/testapp
5675
2. lighttpd -D -f lighttpd-metadata.conf
5776

58-
The metadata has been configured to be available at: http://localhost:8880/metadata.xml.
77+
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/google/metadata.xml (if you followed the instructions above and created the google directory in xt/testapp/IdPs)
5978

6079
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.
6180

xt/testapp/config.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ layout: "main"
22
#logger: "console"
33
appname: "Saml2Test"
44
charset: "UTF-8"
5-
6-
idp: "http://localhost:8880/metadata.xml"
5+
template: "template_toolkit"
76
issuer: "https://netsaml2-testapp.local"
87
url: "https://netsaml2-testapp.local"
98
cert: "sign-certonly.pem"
109
key: "sign-nopw-cert.pem"
11-
cacert: "saml_cacert.pem"
1210
slo_url_soap: "/slo-soap"
1311
slo_url_redirect: "/sls-redirect-response"
1412
slo_url_post: "/sls-post-response"

xt/testapp/lib/Saml2Test.pm

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,52 @@ 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+
51+
config->{cacert} = 'IdPs/' . params->{idp} . '/cacert.pem';
52+
config->{idp} = 'http://localhost:8880/IdPs/' . params->{idp} . '/metadata.xml';
53+
if ( -f 'IdPs/' . params->{idp} . '/config.yml' ) {
54+
my $config_file = YAML::LoadFile('IdPs/' . params->{idp} . '/config.yml');
55+
for my $key (keys %$config_file) {
56+
config->{$key} = $config_file->{$key};
57+
}
58+
} else {
59+
my $config_file = YAML::LoadFile('config.yml');
60+
for my $key (keys %$config_file) {
61+
config->{$key} = $config_file->{$key};
62+
}
63+
64+
}
2765
my $idp = _idp();
2866
my $sp = _sp();
2967
my $authnreq = $sp->authn_request(
@@ -86,7 +124,7 @@ get '/logout-soap' => sub {
86124
cert => 'sign-nopw-cert.pem',
87125
url => $slo_url,
88126
idp_cert => $idp_cert,
89-
cacert => 'saml_cacert.pem',
127+
cacert => config->{cacert},
90128
);
91129

92130
my $res = $soap->request($logoutreq);
@@ -97,7 +135,7 @@ get '/logout-soap' => sub {
97135

98136
post '/consumer-post' => sub {
99137
my $post = Net::SAML2::Binding::POST->new(
100-
cacert => 'saml_cacert.pem',
138+
cacert => config->{cacert},
101139
);
102140
my $ret = $post->handle_response(
103141
params->{SAMLResponse}
@@ -226,7 +264,7 @@ sub _sp {
226264
sub _idp {
227265
my $idp = Net::SAML2::IdP->new_from_url(
228266
url => config->{idp},
229-
cacert => 'saml_cacert.pem',
267+
cacert => config->{cacert},
230268
sls_force_lcase_url_encoding => config->{sls_force_lcase_url_encoding},
231269
sls_double_encoded_response => config->{sls_double_encoded_response}
232270
);

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/lighttpd.conf

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
server.document-root = var.CWD + "/"
22
server.modules = (
33
"mod_openssl",
4+
"mod_rewrite",
45
"mod_proxy"
56
)
67

@@ -34,9 +35,12 @@ setenv.add-environment = ("PATH" => env.PATH )
3435
# request debugging - UNCOMMENT TO ENABLE
3536
debug.log-request-handling = "enable"
3637

37-
$HTTP["host"] == "netsaml2-testapp.local" {
38-
proxy.server = ( "" => ( (
39-
"host" => "127.0.0.1",
40-
"port" => 3000
41-
) ) )
42-
}
38+
url.rewrite-repeat = (
39+
"^/bin/login" => "/consumer-post",
40+
"^/bin/logout(.*)" => "/sls-redirect-response$1"
41+
)
42+
43+
proxy.server = ( "" => ( (
44+
"host" => "127.0.0.1",
45+
"port" => 3000
46+
) ) )

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)