IP-address based weak authentication
Ideas on how one might implement an IP-address-based weak authentication mechanism for uPortal.
"I just want you to know who I am" – "Iris", the Goo Goo Dolls (:58)
High Level Discussion
There's a whole lot of public content
There's a great deal of public information available. The Web, for instance, is largely publicly available information. Some amount of this information is suitable for presentation as uPortal channels. One way we customize the public information that individual users receive – one way we provide value in portals – is by allowing the user to authenticate and receive a layout populated with information that she has chosen or someone has chosen for her from the universe of available content, which includes both public content (authentication was for the purpose of identifying her preference to see this particular public content) and private content (authentication was for the purpose not only of identifying her preference to see this particular content but was also for the purpose of authorizing her to see the content.)
We can make meaningful gueses about what public content a user might want to display before she logs in
While there is no substitute for the full power of user authentication to see private content and a truly personalized, end-user-configured, layout, we can nonetheless make some educated guesses about what in the universe of available content we wish to present to a non-authenticated user.
A persistent per-user cookie
Conceivably, uPortal could place a persistent per-user cookie that would inform the guest layout. It might result in the user being "logged in" and those channels that display public information would render – if the user layout itself is not regarded as private information. Alternatively, one might allow the user to configure a custom guest layout consisting only of publicly available channels.
IP address tricks
The user IP address conveys a lot of information. From it, you might be able to determine:
- that a computer was registered to receive an IP address, and by whom it was registered
- whether the computer is an institutional cluster computer, if so what kind and where
- whether the computer is on a residential or administrative subnet
- what institution the computer is at, in the case of a uPortal serving multiple institutions.
- which School within a University the request is likely coming from
Of course, it's inappropriate to use IP address for authentication – there are too many well know IP address spoofs – but it's a plausible way to filter and customize public information.
We might use this IP address information to select an entire layout, or we might use it to inform the content to be displayed by particular channels.
Network Registration
At Yale one year we placed a channel on our guest layout front page that, based on the IP address of the request, would detect the case where the request was likely coming from an unregistered computer on a student subnet and in that case displayed an invitation to "Click here to register your computer!".
Single Sign On
Incidentally, Single Sign On has something to offer here. If a user has only to authenticate once and then her entire web session is authenticated, and if resources she accesses can detect this authenticated state and jump directly to logged in state, then the need to play these non-logged-in guessing games is lessened. Logging in is a good thing. The authenticated experience should be so compelling, so effectively present exactly what the user didn't even realize she was eager to know, that users should be logging in.
See also
See also Authentication versus Customization.
On predicating guest content display upon requestor IP address
Yale's SAM Kiosks
If you visit YaleInfo Portal from Service and Maintenance Kiosks distributed throughout campus, YaleInfo detects that the IP address of the kiosk is in the set of SAM Kiosk addresses and switches to present an alternate guest layout. This trick allowed Yale to rapidly deploy an alternative guest layout, using the existing uPortal installation to provide a second public view customized to the particular needs of this kiosk project.
Here's an alternative implementation story that treats IP Address as an authentication mechanism:
Use Case
On the basis of the IP address, we will categorize our users into one of three categories:
User categories |
---|
Yale user |
Rutgers user |
unknown |
We have a different Layout consisting of channels presenting public information that we want to associate with each of these groups.
When a user accesses our portal, he is to be categorized based on his IP address into one of these three categories. The portal must present the layout and content associated with that category. The portal must also offer the opportunity to authenticate. Authentication results in a layout based on the user's authenticated identity: a Yale user visiting Rutgers will receive the Rutgers guest layout but upon authentication will get the Yale layout if he has not personalized or his very own layout if he has edited his layout.
When users truly authenticate, they will do so using CAS.
Implementation
Model the categories of un-authenticated users as dummy users.
We already have a generic "guest" user. Additionally we will have a yale_guest and a rutgers_guest.
We assign these users the layouts we want to present to their respective category of users.
Implement the Authentication
We will have a Union authentication context. That union will be configured to stop on success. In the union will be the YaleCASFilteredContext first. Second it will have the IPAddressContext, which we are about to invent.
YaleCASFilteredContext is well documented elsewhere. It gets first dibs because we want a user's explicit (stong) authentication to override the weak IP-address based "authentication" we're about to implement.
IPAddressContext will examine the user's IP address and authenticate as either yale_guest or rutgers_guest as appropriate. It does some clever pattern matching on the IP address.
The HttpServletRequest isn't available to the ISecurityProviderFactory that we're going to write. So how are we going to get the remote address?
The uPortal SecurityProvider API really wants to be about specifying credential tokens that are request parameters. You specify your credential tokens in security.properties, and then the Authentication service will pass the appropriate credentials to your particular ISecurityProviderFactory, which will in turn instantiate an ISecurityProvider, which we will finally interrogate to determine if the user has successfully authenticated. So how are we going to get the remote address down into our ISecurityProvider instance?
Here's what we're going to do. We're going to put a filter in front of our uPortal front page, in front of everything else. That filter is going to examine the request. If the request has a session, it's going to do nothing. If the request already has the request parameter "remote_addr" set, it's going to do nothing. But if there is not already a session and this parameter is not present, it's going to get the remote address of the request, and then send a redirect to the browser telling it to redirect to our Login servlet with the request parameter remote_addr set to the String representation of that IP address. (We're also going to retain any other request parameters, in case we somehow just intercepted and redirected a request for the Login servlet that was presenting other credentials that are going to trump the IP address anyway).
In security.properties, we set remote_addr as the credential to be passed to our IPAddressContext.
In our IPAddressContext, we extend ChainingSecurityContext. When we are asked to authenticate, we can get the IP address as a String by examining our "opaque credentials":
public class IPSecurityContext extends ChainingSecurityContext { ... public synchronized void authenticate() throws PortalSecurityException { String ipAddrString = new String( this.myOpaqueCredentials.credentialstring); this.isauth = false; String userName = ipAddrToUserResolver.resolve(ipAddrString); if {userName != null} { this.myPrincipal.setUID(userName); this.isauth = true; } super.authenticate(); } ... }
ipAddrToUserResolver is the thing that knows how to map from IP addresses to our guest users when appropriate. It returns null when it has no mapping for the given IP address. We probably provided our IPSecurityContext an intance of an interface implementing this functionality when our factory constructed it, so that IPSecurityContext is not dependent upon any particular implementation of this functionality.
Guests users need to be able to truly authenticate
We place channels in the special layouts of yale_guest and rutgers_guest providing an appropriate login UI. Since we're using CAS, we presumably use an image representing a login button that links off to CAS with our uPortal Login URL as the "service" parameter. If we weren't using CAS, we'd have a different UI in this channel, such as a username and password form that posts to the uPortal Login servlet for Simple authentication.
Guests must not change their layouts
We edit the CHeader channel to check for the usernames of our dummy users and fail to present the user preferences UI – e.g., the link to Preferences mode.
Presumably if we're really conscientious we'll also go find the other end of that link we're ommitting and ensure that even a clever hacker who reconstructed the URL to access the preferences UI wouldn't be able to get that UI to render as these users. But first pass, we'll just inconvenience a would-be portal defacer by removing the link.
(Incidentally, this is an example of why it's important that CHeader exist and be a real IChannel – it can consider ChannelData conveying things like the username.)
Hey! We're done!