Channels ▼
RSS

Web Development

Implementing Secure Login, Part 2


The Mediators

Finally let's look at the mediators. The containing page instantiates an <iframe> that sources the login-request mediator (Listing Five) to send a message to the login object. loginRequestMediator.html has the same origin as loginPanel.html, which defines the login object. As you can see, the main thing the mediator code does is call the login(...) function that we were just looking at — the one in loginPanel.html.

Rounding out the discussion, the login mediator (Listing Six) handles communication from the login object to the containing panel. It works the same as the other mediator, but now it's calling methods of the listener object that I talked about at the beginning of this article. The <iframe> that sources the login mediator uses the same origin as the containing page.

Listing Five

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">	

<!-- This class is used by the login application to talk to the
	 the surrounding page. It should be loaded from the same
	 domain as that used by the main page. The url arguments are:
	 
	 	action=[login|logout|recoverPassword]
		arg=loginToken 		(for login)
		arg=recoveryMessage (for "recoverPassword")
	 	
	 The action is a message that's sent to the top.loginListener
	 object. For example, given the url:
	 
	 	http://localhost:8080/loginMediator.html?action=login&arg=theToken
	 
	 the mediator will effectively execute
	 
	 	top.loginListener.login("theToken");

	Note that we can't use the HTML5/Javascript postMessage method, here,
	because in Safari at least, a child frame can't use postMessage to
	talk to its parent, which is exactly what we need to do. 
-->

<html>
<head>
	<script type="text/javascript" language="javascript">
	function run()
	{
		var arguments = document.location.search.substring(1);  // the "substring(1)" removes the ?
		var groups;
		groups = arguments.match( /action=([^&]*)/); var action	= groups ? groups[1] : null ;
		groups = arguments.match( /arg=([^&]*)/); 	 var arg	= groups ? groups[1] : null ;
		send( action, arg);
	}
	
	function send( action, arg )
	{
		if( window.top.loginListener )
		{
			if( action == "login" )
				window.top.loginListener.login( arg );
			else if( action == "logout" )
				window.top.loginListener.logout();
			else if( action == "recoverPassword" )
				window.top.loginListener.recoverPassword( arg );
		}
		else
		{
			// SetTimeout is inherently dangerous because it's effectivly running
			// eval() when the timeout expires. Imagine, for example, that the
			// arg string supplied in the url looks like this:
			// 		"foo" ); doSomethingEvil(
			// the argument to set time out is then:
			//		send("someAction", "foo" ); doSomethingEvil();
			// which is bad. This exploit isn't possible if we don't accept
			// either an action or argument string which holds a close parenthesis
			// that isn't preceded by an open parentheses, thus the test, below.
			
	        var parenthesis = /[^\(\)]*([\(\)])/;
	        var result 	    = action.replace( parenthesis, "$1" );
			if( result.charAt(0) != ')' )	// then the action is safe, so execute it
			{
				result = arg.replace( parenthesis, "$1" );
				if( result.charAt(0) != ')' )	// then arg is safe
					setTimeout( 'send("'+ action + '","' + arg +'")', 500 );
			}
		}
	}	
	</script>
</head>
<body onload='run()'>
</body>
</html>

Listing Six

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">	

<!--	
Instantiate this mediator in an iframe to request that the login panel log you in.
The mediator must be loaded using the same protocol (e.g. https) and domain name as
the loginPanel, and the iFrame that holds the loginPanel must be named "loginPanel"

For example, your main web page would instantiate the login panel like this:
  
	<iframe src="https://secure.iexperiment.net/work/loginPanel.html" name="loginPanel"></iframe>
	<div id='requestPanel'><div>

Note that you must use name=, not id=, to identify the iframe. You then request a login from javascript
as follows:

	var target = document.getElementById('requestPanel');
	target.innerHTML = "<iframe src='https://secure.iexperiment.net/work/loginRequestMediator.html?username=harpo&password=swordfish&remainLoggedIn'></iframe>";
	
The "remainLoggedIn" argument causes you to remain logged in. If absent, you will not remain logged in.

If the username and password arguments are both missing, then you'll be logged out.
-->

<html>
<head>
	<script type="text/javascript" language="javascript">
	function run()
	{
		var arguments = document.location.search.substring(1);  // the "substring(1)" removes the ?
		var groups;
		
		groups = arguments.match( /username=([^&]*)/); 		var username = groups ? groups[1] : null ;
		groups = arguments.match( /password=([^&]*)/); 		var password = groups ? groups[1] : null ;
		groups = arguments.match( /remainLoggedIn/); 		var remain   = groups ? true	  : false ;
		
		if( username == null && password == null )
			top.frames['loginPanel'].logout(); 							// remain-logged in is false.
		else
			top.frames['loginPanel'].doLogin( username, password, remain ); // remain-logged in is false.
	}
	</script>
</head>
<body onload='run()'>
</body>
</html>

Conclusion

So that's it for login. You now have a secure, self-contained module that you can just plug into your application with about five minutes work. You'll need to do some additional housekeeping, of course (you need to install a certificate into your server so that you can handle https communication and set up a secure subdomain, for example), but most of the grunt work is done for you. Enjoy!

Related Articles

Secure Login in AJAX Applications

Getting Started With the Cloud: Logging On With Google OAuth

Getting Started with Google Apps and OAuth

Getting Started with The Cloud: The Ecosystem


Allen Holub provides technical training, OO design and agile-process consulting, and web application/SaaS development services. He is the author of Holub on Patterns: Learning Design Patterns by Looking at Code (also available for Kindle), C+ C++: Programming With Objects in C and C++, and numerous articles for SD Times, JavaWorld, and IBM Developer Works. Contact him via http://www.holub.com/contact.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 
Dr. Dobb's TV