...
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
...
Panel | ||||||
---|---|---|---|---|---|---|
| ||||||
Use CaseOn the basis of the IP address, we will categorize our users into one of three categories:
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. ImplementationModel 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 AuthenticationWe 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 ipremote_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":
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 authenticateWe 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 layoutsWe 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! |