|
REST based authentication - Solution by Nano Documet
|
Introduction
In this page you will find a simple and short solution that allows you to provide a friendly logout functionally with just clicking a link when working with AuthType from Apache.
I have tried with both Basic and Digest Authentication Types and they work the same way.
Updated June 18th, 2006
To check for the changes needed when using Basic AuthType click here
Appendix
So, let's go directly to the solution.
Browsers that work with this solution
- Windows Internet Explorer 6. On Windows XP
- Mozilla Firefox 1.5.0.4. On Windows XP
- Avant Browser 10.2 Build 52. On Windows XP Updated June 11th, 2006
- Mozilla Firefox 1.5.0.3 for Linux (Thanks to Jan Eri)
- Epiphany 1.8.5 for Linux (Thanks to Jan Eri)
- Other browsers have been not tried.
Requirements
- Apache Server (has been tested on Apache/2.0.55 Win32)
- Access to .htaccess file (for a given directory)
Tested File Structure
Physical files
- index.html (gives you the option to login, not protected)
- authenticated.html (protected with desired realm and other authentication stuff. It is where you are redirected after login)
- logged_out.html (not protected. This is used for logout)
From <files> directive (Only two needed)
- .login (protected with desired realm and other authentication stuff)
- .force_logout_offer_login_mozilla (protected it has same authentication configuration as .login)
This is my .htaccess file
See Digest .htaccess
#==================================
# And disable caching, always validate against server.
Header append Cache-Control "no-cache"
# Support the biggest software vendor on the planet which produces
# the biggest load of crap
BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
ErrorDocument 401 /rest/index.html
# Only when user tries to access .login, ask user for authentication
<Files .login>
AuthType Digest
AuthName "yourDomain"
AuthDigestFile "C:/.../rest/.htdigest"
Require valid-user
# If user is already authenticated, redirect to protected page
RewriteEngine on
RewriteCond %{REMOTE_USER} !=""
RewriteRule ^.*$ /rest/authenticated.html [R]
</Files>
<Files authenticated.html>
AuthType Digest
AuthName "yourDomain"
AuthDigestFile "C:/.../rest/.htdigest"
Require valid-user
</Files>
<Files .force_logout_offer_login_mozilla>
AuthType Digest
AuthName "yourDomain"
AuthDigestFile "C:/.../rest/.htdigest"
Require valid-user
</Files>
#==================================
This is my logged_out.html file
==============logged_out.html====================
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>logged_out.html</title>
<link rel="stylesheet" href="style.css" />
</head>
<p>This webpage is: logged_out.html</p>
<p>To login again click here <a href=".login">Login</a></p>
<p>To go back to the main page click here <a href="/rest">Back to main page</a></p>
<script language="javascript" type="text/javascript">
try{
var agt=navigator.userAgent.toLowerCase();
if (agt.indexOf("msie") != -1) {
// IE clear HTTP Authentication
document.execCommand("ClearAuthenticationCache");
}
else {
var xmlhttp = createXMLObject();
xmlhttp.open("GET",".force_logout_offer_login_mozilla",true,"logout","");
xmlhttp.send("");
xmlhttp.abort();
}
// window.location = "/rest/";
} catch(e) {
// There was an error
alert("there was an error");
}
function createXMLObject() {
try {
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
// code for IE
else if (window.ActiveXObject) {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
} catch (e) {
xmlhttp=false
}
return xmlhttp;
}
</body>
</html>
==============logged_out.html====================
Explanation
Because the .login webpage is protected it requires the browser to present credentials
So, at the beginning you will see a pop-up for username:password
So, what can happen here?
a) You give the wrong credentials, then the pop-up appears again. This comes from the section from .htaccess
b) You give the right credentials, then you are authenticated and authenticated.html is shown.
# If user is already authenticated, redirect to protected page
RewriteEngine on
RewriteCond %{REMOTE_USER} !=""
RewriteRule ^.*$ /rest/authenticated.html [R]
c) You click Cancel. The .htaccess file redirects you to the index.html again from the statement
ErrorDocument 401 /rest/index.html
Now, let's assume you have given the right credentials, so you are in a protected webpage (it could be a set of webpages).
And from this webpage you have a logout link that redirects you to logged_out.html
So what happens now?
1) If you have Internet Explorer the credentials will be erased using the statement below
if (agt.indexOf("msie") != -1) {
// IE clear HTTP Authentication
document.execCommand("ClearAuthenticationCache");
}
2) If you have Firefox the credentials will be erased because of the following code
else {
// Let's create an xmlhttp object
var xmlhttp = createXMLObject();
// Let's get the force page to logout for mozilla
xmlhttp.open("GET",".force_logout_offer_login_mozilla",true,"logout","logout");
// Let's send the request to the server
xmlhttp.send("");
// Let's abort the request
xmlhttp.abort();
}
// Let's redirect the user to the main webpage
window.location.href = "/rest/";
From above, the required values are:
xmlhttp.open()
- Method: GET (could be POST too)
- Webpage: .force_logout_offer_login_mozilla, needs to match the statement in .htaccess file
- Asynchronous: "true". To allow the rest of the page continuing running and not waiting for response after send
- Username: "logout". It could be anyone that is not in the .htdigest file
- Password: "logout". Really not necessary
xmlhttp.send("")
- It is going to get the webpage .force_logout_offer_login_mozilla with wrong credentials
xmlhttp.abort()
- Aborts the sending request, but the browser did not get the response. Thus, keeps wrong credentials on cache
window.redirect
- Just to go back to main page from any browser
See it working (Digest AuthType)
Click below to login. Use following credentials:
Username: nano
Password: nano
Login
Appendix
#==================================
1. # And disable caching, always validate against server.
2. Header append Cache-Control "no-cache"
3.
4. # Support the biggest software vendor on the planet which produces
5. # the biggest load of crap
6. BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
7.
8. ErrorDocument 401 /rest/index.html
9.
10. # Only when user tries to access .login, ask user for authentication
11. <Files .login>
12. AuthType Basic
13. AuthName "yourDomain"
14. AuthUserFile "C:/.../rest/.htpasswd"
15. Require valid-user
16.
17. # If user is already authenticated, redirect to protected page
18. RewriteEngine on
19. RewriteCond %{REMOTE_USER} !=""
20. RewriteRule ^.*$ /rest/authenticated.html [R]
21. </Files>
22.
23. <Files authenticated.html>
24. AuthType Basic
25. AuthName "yourDomain"
26. AuthUserFile "C:/.../rest/.htpasswd"
27. Require valid-user
28. </Files>
29.
30. <Files .force_logout_offer_login_mozilla>
31. AuthType Basic
32. AuthName "yourDomain"
33. AuthUserFile "C:/.../rest/.htpasswd"
34. Require valid-user
35. </Files>
#==================================
The changes done are:
Lines 12, 24, and 31: From AuthType Digest to AutheType Basic
Lines 14, 26, and 33: From AuthDigestFile to AuthUserFile
Notice that also in lines 14, 26, and 33 the file changes accordingly
Those changes are required for Apache versions prior to 2.2
2. Simpler solution: Updated June 18th, 2006
Notice that you can group all your private files under a protected folder and make a link that access a real file. This way you will not need to define a set of directives for each file
and instead all the files are protected at once.
Then on your protected files you can make a link to the same logged_out.html page as above and make this one try to access any valid protected webpage.
This is very helpful when you have extra options in your protected folder (like scripts execution) and you want this dynamic content also to be capable of having the logout feature.
Acknowledgments
Last updated June 18th, 2006
Contact me: nanodocumet [at] gmail [dot] com