-
Notifications
You must be signed in to change notification settings - Fork 3
This is a short guide how to set the common login gui and few lines about how to play with and what to expect from shibboleth attributes.
In order to use the common login capabilities, you need to complete several steps.
- Create login/logout code for you webapplication. When the user logs in you will receive (either in environment or in http headers) a bunch of attributes about him (eg. name, email), so the logged in state should be based on these. For more details see Shibboleth Section
- You need to tell apache that the code created in previous step is interested in shibboleths attributes. see Apache section
- You need to include various files (.css,.js) for the gui. see includes section
- Last you need to do service specific setup for the gui. At least you must fill the url of the login code, you also might want to set a display name. see Service specific configuration
Most of the sections contain example setup done for the repository, so whenever you see /shibboleth-login or /aai_test.cgi you have to use your own login url instead.
You need to have jQuery(any version should be fine; tested with 1.7), DiscoJuice (.css, .js) and a script which sets up discojuice. You can use this code as is (unless you've already included jQuery somewhere else). jQuery needs to be defined before discojuice-stable.
<link rel="stylesheet" type="text/css" href="https://static.discojuice.org/css/discojuice.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js" type="text/javascript"> </script>
<script src="https://engine.discojuice.org/discojuice-stable.min.js" type="text/javascript"> </script>
<script src="https://ufal-point.mff.cuni.cz/aai/aai.js" type="text/javascript" > </script>
The popup will be attached to all anchors with class signon. So you need to have at least one on your page. eg:
<a href="#" class="signon">Login</a>
The aai script requires you to set certain variables - at least the target (see the complete list & description lower). You can set these either in another .js file (eg. aai_config.js) or have them inline the .html.
Example of minimal aai_config.js if your login code is at "https://ufal-point-dev.ms.mff.cuni.cz/aai_test/aai_test.cgi"
jQuery(document).ready(
function() {
opts = new function(){
this.target = "https://ufal-point-dev.ms.mff.cuni.cz/aai_test/aai_test.cgi";
this.serviceName = "Test Service Login";
};
if(!window.aai){
throw "Failed to find aai. Did you include all that is necessary?";
}
aai.setup(opts);
});
Detailed list of what you can set up
Variable name | meaning | default |
---|---|---|
target | Url of the login script/application - the part of your code that will read shibboleths attributes and search/create users based on them. eg. https://ufal-point-dev.ms.mff.cuni.cz/xmlui/shibboleth-login This is what you need to set in apache as requiring a session (see below) |
NONE, you have to specify this |
serviceName | A string to be displayed in heading of the popup eg. | "", you want to specify this |
localauth | html snippet containing form to handle local (non shibboleth) logins. | none, you might want to specify this |
You shouldn't be concerned about these below except for special cases
Variable name | meaning | default |
---|---|---|
host | hostname with protocol | "https://" + window.location.hostname; |
responseUrl | Page supplied by discojuice to circumvent possible same origin policy problems. Should not contain protocol. | this.host.substr(this.host.indexOf(":") + 1) + "/xmlui/themes/UFAL/lib/html/disco-juice.html?"; |
ourEntityID | Entity id of our SP. Set up in shibboleth; sent to federations. | "https://" + window.location.hostname + "/shibboleth/eduid/sp"; |
metadataFeed | Url of jsonp file containing info about idps | this.host + "/xmlui/discojuice/feeds"; |
textHelp | Link that displays help | Please help, I cannot find my provider |
textHelpMore | Text of the help | If your institusion is not connected to this service, you may create a new account using any of the guest login providers. You also may contact your instituion to request being connected with this service. |
More complicated configuration example to be used by repository on ufal-point and all repository instances on ufal-point-dev, including the localauth snippet.
jQuery(document).ready(
function() {
opts = new function(){
//if ever port is needed (eg. testing other tomcat) it should be in responseUrl and target
this.port = (window.location.port == "" ? "" : ":" + window.location.port);
this.host = window.location.protocol + '//'
+ window.location.hostname
this.repoPath = jQuery("a#repository_path").attr("href")+"/";
this.target = this.host + this.port + this.repoPath;
this.responseUrl = "//" + window.location.hostname
+ this.port
+ this.repoPath
+ "themes/UFAL/lib/html/disco-juice.html?";
this.metadataFeed = this.target + "discojuice/feeds";
this.serviceName = "LINDAT Repository";
this.localauth =
'<form method="post" action="'+this.target+'password-login"> '+
'<p>Sign in using account at <strong>ufal-point.mff.cuni.cz</strong>.</p>' +
'<p style="margin: 5px; color: #888" ><input type="text" name="login_email" style="font-size: 160%; width: 100%" id="login" /> <label for="login">E-Mail Address</label></p>' +
'<p style="margin: 5px; color: #888" ><input type="password" name="login_password" style="font-size: 160%; width: 100%" id="pass" /> <label for="pass">Password</label></p>' +
'<p style="margin: 5px; color: #607890; text-decoration: underline;"><a href="'+this.target+'forgot">Forgot your password?</a></p>'+
'<p style="" ><input type="submit" style="margin: 20px 2px" name="submit" value="Sign in" /></p>' +
'</form>';
this.target = this.target + "shibboleth-login";
};
if(!window.aai){
throw "Failed to find aai. Did you include all that is necessary?";
}
aai.setup(opts);
});
You need to "tell" apache that:
- It needs to "contact" shibboleth when accessing your login code
- ensure there is an existing session, when your login script/application is accessed.
To do this configure the Directory/Location/LocationMatch of your login script/code (see target above) like in the following example (where /xmlui/shibboleth-login is the part of the repository which deals with shibboleth attributes and sets inner application state to "logged in"):
Example configuration for repository you should change only the "path"
<Location /xmlui/shibboleth-login>
AuthType shibboleth
ShibRequestSetting requireSession 1
require valid-user
</Location>
By default shibboleths attributes will be available in environment. If you need them (also) in HTTP headers add
ShibUseHeaders On
on the next line after the 'reguireSession'. But the names might slightly change compared to what's listed in next section (they might get prefixed by "HTTP_").
Anyway it is a good idea to have a quick way to display environment/http headers. Through cgi with perl it's as easy as:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Dumping environment\n";
foreach $key (sort keys(%ENV)) {
print "$key = $ENV{$key}<p>";
}
If everything goes OK, the IDP authenticates the user and sends you information about him - his attributes. These are available in environment and/or in http headers (see the apache section). The sad thing is you are not guaranteed to receive some "stable" (or ensured) set of attributes. If you check https://ufal-point.mff.cuni.cz/secure/attributes.xml you can see list of (attributes, IDP) combinations we've seen since may. You can see that the sets change over time (they usually get bigger - that's a good thing) and you can see the differences between set sizes based on IDPs.
What you need to take from this is to prepare your code in such a way that it doesn't break when the attribute is not present. If you didn't receive all that you need, be prepared to ask the user to supply it. Eg. in repository if we don't receive an email (but we did receive some persistent id), we ask the user to fill (and confirm) the email otherwise he would not be logged in.
If you receive so little that you are unable to even ask for the missing stuff, eg. you know that he had credentials at the IDP (thus is authenticated) but other than that nothing (or info such as student/faculty) - you have no way of recognizing him if he comes again (thus anything he filled the first time is useless), offer some explanation why the login can't continue, suggest to ask his IDP if he's releasing attributes for our service, as a least resort (if possible in your service) try creating local account.
Follows a list and description of the more frequent/really useful attributes. These will be the names under which you should see them in your environment, but once again have some viewing routine prepared.
Name | Description | Comment |
---|---|---|
eppn | Id/Name that is not service dependent | Imagine it's your CAS number @cuni.cz, you are using all over the place. Compare to persistent-id. |
persistent-id | Targeted id, meaning it's some (opaque) identifier specially created for our service provider | Looks like random string. Because ufal-point and ufal-point-dev are two different service providers you can't migrate/merge users from one to the other - it would be possible with eppn. |
persons email | ||
sn | Surname | * |
givenName | * | |
cn | Common (?) name | Good substitute for sn+givenName * |
Others like affiliation, entitlement, schacHomeOrganization, o, org-dn, orgunit-dn might help if you need to do decisions based on where the user is from (eg. provide more for colleagues from cuni), or what is their status (eg. students can access restricted resources, employees can modify them) |
Identifying UFAL people is not an easy task, check the repository issue tracker to get some idea.
Watch for correct character encoding/conversion when displaying the attributes (especially those marked with a *)
self notes: do we require ssl?, shibboleth on /, ie. globally for all, somehow possible but can mess up .htaccess auth and you still need to require the session in some place.
The case study explains, how the Cesilko application can use Shibboleth based authentication mechanism to allow access to the translation service. The Cesilko has different behavior for "authenticated users" and "unauthenticated users". The Cesilko allows authenticated users to perform translation of texts with arbitrary size. Unauthenticated users have a 5000 character restriction on the translation operations.
The Cesilko service pages are available at
/var/www/services/cesilko
in both ufal-point
and ufal-point-dev
.
There are two major steps required to include AAI for Cesilko.
The Configuration step is common for any application that want to include AAI. The Configuration step includes certain header information that is necessary for all the applications to access the AAI, in our case Shibboleth.
Managing Users Login section explains, how to use Shibboleth based authentication to implement user based session for Cesilko. The authenticated users can send unlimited translation requests to Cesilko service.
In the Apache configuration file, you have to add where the user credential information should be passed to when a user initiates the login session at Cesilko.
<Location /services/cesilko/cesilko_login.php>
AuthType shibboleth
ShibRequestSetting requireSession 1
ShibUseHeaders On
Require valid-user
</Location>
cesilko_login.php
file is where the users' credentials will be passed from the login session where the user provides his identity information.
This section explains what should be added in the Cesilko webpages to access the Shibboleth. More general information about what should be included in any service is explained in the Sections : Includes and Service Specific Configuration.
There are 3 things one should keep in mind when adding the configuration info for any service.
- add session preamble (if required)
- add header/script in the service page
- add login link
session preamble:
There are many ways the login session can be managed. In PHP, it is accomplished through PHP Sessions. So, the following code is added to all the web pages in Cesilko at the top (even before the <html> tag). We use PHP Session based mechanism to both access the Shibboleth user credentials as well to implement user sessions in Cesilko once the user is authenticated.
<?php
session_start();
?>
Add the above code in all the web pages. The above code merely starts a session. But we have to manage the session according to the user credentials which we can obtain through login process. We can maintain and manage sessions based on user credentials.
header/script:
The main webpage of the Cesilko is index.php
. From index.php
, the login session is initiated. So, this file should include the header information which allows to initiate the Shibboleth login session.
The following code is added inside <head>...</head>
of the index.php
.
<link rel="stylesheet" type="text/css" href="https://static.discojuice.org/css/discojuice.css" />
<script src="https://engine.discojuice.org/discojuice-stable.min.js" type="text/javascript"> </script>
<script src="./aai.js" type="text/javascript" > </script>
<script>
jQuery(document).ready(
function() {
opts = new function(){
this.target = "https://" + window.location.hostname + "/services/cesilko/cesilko_login.php";
this.serviceName = "Cesilko";
};
if(!window.aai){
throw "Failed to find aai. Did you include all that is necessary?";
}
aai.setup(opts);
});
</script>
Login Button or Login Link:
Add the following which initiate the login session.
<a href="#" class="signon">Login</a>
We can go through the login session implementation of Cesilko step by step.
After clicking "Login", the Shibboleth appears,
Once the user is authenticated from the above step, the user credentials will be passed to the "cesilko_login.php" as we have already mentioned in the section Configuration.
The php file cesilko_login.php
receives the authenticated user's information in the global hash variable called
- "_SERVER". We are mainly interested in the following two variables,
- _SERVER["givenName"] (which holds the user's first name)
- _SERVER["mail"] (user's email)
For our purpose the above two variables are enough.
The availability of the above two variables indicate that the user is a valid user. So,we just pass the user credentials to the Cesilko main page through the already established session. The above two variables must be stored in session variables. The session variables will be alive for the already established session no matter which webpage you access. The session variables can be recognized with the prefix _SESSION.
<?php
session_start();
$protocal_name = 'https://';
$server_name = $_SERVER['SERVER_NAME'];
$cesilko_page = '/services/cesilko/index.php';
$cesilko_uri = $protocal_name . $server_name . $cesilko_page;
$username = '';
$email = '';
$authenticated = False;
if (isset($_SERVER['givenName']) || isset($_SERVER['mail'])) {
$authenticated = True;
}
if (isset($_SERVER['givenName'])) {
$username = $_SERVER['givenName'];
}
if (isset($_SERVER['mail'])) {
$email = $_SERVER['mail'];
}
if ($authenticated) {
# set the session variables
$_SESSION['username'] = $username;
$_SESSION['email_id'] = $email;
$_SESSION['login_attempt'] = 'fresh';
header('Location: ' . $cesilko_uri . '?login=yes');
}
else {
header('Location: ' . $cesilko_uri . '?login=no');
}
?>
If the login is success
The page will be redirected to
/services/cesilko/index.php?login=yes with three session variables:
- $_SESSION['username']
- $_SESSION['email_id']
- $_SESSION['login_attempt']
If the login fails
The page will be redirected to
/services/cesilko/index.php?login=no
We assume that the user is authenticated and the page is redirected from cesilko_login.php
with the _SESSION variables. There is another variable "login" which would also have been passed during the redirection with successful login. The "login" variable can be accessed through _GET.
The redirection such as
/services/cesilko/index.php?login=yes
with _SESSION variables
$\_SESSION\['username'\]="Loganathan"
$\_SESSION\['email\_id'\]="xxxxx@ufal.mff.cuni.cz"
$\_SESSION\['login\_attempt'\]="fresh"
would bring us the following redirected page
Through the already established session and with the availability of $_SESSION variables, we adjust the behaviour of Cesilko. In our case, if an authenticated user is accessing the Cesilko (as indicated by the availability of $_SESSION variables), the Cesilko allows the unlimited translation service. If an unauthenticated user is accessing the Cesilko service (as indicated by the unavailability of $_SESSION variables), the Cesilko provides translation of upto 5000 characters.
The Cesilko provides "logout" link to terminate the already established user session. The "logout" link internally destroys the current session by calling session_destroy();
in the script. This undefines all the $_SESSION variables. Thus Cesilko no longer remembers the user credentials. Once the user is logged out, the Cesilko provides only limited translation services (i.e. texts of upto 5000 characters).