blob: f5442b4fa4218c7c6c468804bb66d67d2f64d9d0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package flex.messaging.security;
import com.ibm.websphere.security.UserRegistry;
import com.ibm.websphere.security.WSSecurityException;
import com.ibm.websphere.security.auth.WSLoginFailedException;
import com.ibm.ws.security.core.ContextManager;
import com.ibm.ws.security.core.ContextManagerFactory;
import flex.messaging.FlexContext;
import flex.messaging.log.Log;
import flex.messaging.log.LogCategories;
import javax.security.auth.Subject;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* To setup WebSphere 5.1 for authentication testing:
*
* 1) Install WebSphere 5.1
* 2) Create two files, users.props and groups.props
* (examples in resources/security/websphere) and place them in a directory
* under your WS install.
* 3) Using the Admin webapp:
*
* Security > Global Security
* Check Enabled
* Check Enforce Java 2 Security
* Set Active User Registry to Custom
* Click OK
*
* Either the admin app will tell you to setup your Custom or you should
* go to Security > User Registries > Custom
*
* Server User ID should be one of your users from your users.props
* Server User Password should be the matching password from users.props
* Customer Registry Classname by default is com.ibm.websphere.security.FileRegistrySample
* Go to Custom Properties
* Add a prop "groupsFile" that points to your groups.props: e.g., c:/websphere5.1/AppServer/security/groups.props
* Add a prop "usersFile" that points to your users.props: e.g., c:/websphere5.1/AppServer/security/users.props
*
* Click OK
*
* 4) Install your Flex EAR. You may need to go into its Session Settings
* page and enable session security there?
*
* 5) In <websphere_dir>/java/jre/lib/security edit java.policy and add something
* like the following:
*
grant codeBase "file:${was.install.root}/installedApps/MCHOTIN03/Flex2Ear.ear/secure.war/-" {
permission java.security.AllPermission;
};
* This gives your webapp all the permissions it needs (possible that it could have
* been narrowed down further).
*
* 6) Edit java.security in teh same directory to add the following entries
security.provider.1=com.sun.net.ssl.internal.ssl.Provider
security.provider.2=sun.security.provider.Sun
* Update the entries below it so they're ordered right.
* Copy jsse.jar and jcert.jar into java/jre/lib/ext (I think)
* This will get the Flex Proxy to start correctly
*
* Restart your WebSphere, cross your fingers!!!
*
*/
/**
* Authenticates against WebSphere but does not store the authenticated
* user in the HttpServletRequest for http attempts due to the container
* not providing a mechanism for access.
*/
public class WebSphereLoginCommand extends AppServerLoginCommand implements PrincipalConverter {
/**
* {@inheritDoc}
*/
public Principal doAuthentication(String username, Object credentials) {
Principal principal = null;
try {
String password = extractPassword(credentials);
if (password != null) {
ContextManager contextManager = ContextManagerFactory.getInstance();
Subject subject =
contextManager.login(contextManager.getDefaultRealm(),
username, password);
if (subject != null) {
//setting the caller subject really doesn't apply for long
//it appears to be removed later as each call to
//ContextManagerFactory.getInstance()
//returns a new instance and we cannot get the real context
//and assign values that will be re-used.
//this also means that the HttpServletRequest will not have the
//information that we've assigned, hence we store this contextManager
//in the Principal for later use
contextManager.setCallerSubject(subject);
principal = new WSLCPrincipal(username, contextManager, subject);
}
}
} catch (WSLoginFailedException wsLoginFailedException) {
if (Log.isDebug()) {
Log.getLogger(LogCategories.SECURITY).debug("WebSphereLoginCommand#doAuthentication() failed: " + wsLoginFailedException.toString(), wsLoginFailedException);
}
} catch (WSSecurityException wsSecurityException) {
if (Log.isDebug()) {
Log.getLogger(LogCategories.SECURITY).debug("WebSphereLoginCommand#doAuthentication() failed: " + wsSecurityException.toString(), wsSecurityException);
}
}
if (Log.isDebug() && principal != null) {
Log.getLogger(LogCategories.SECURITY).debug("WebSphereLoginCommand#doAuthentication(). Principal: " + principal + ", Principal class: " + principal.getClass().getName()
+ ", Principal identity: " + System.identityHashCode(principal));
}
return principal;
}
/**
* {@inheritDoc}
*/
public boolean doAuthorization(Principal principal, List roles) {
//unfortunately we cannot seem to get the user stored
//in the context so the request will never have the information
//that we've assigned, therefore we have to do this
//every time
if (principal == null)
return false;
if (Log.isDebug())
Log.getLogger(LogCategories.SECURITY).debug("WebSphereLoginCommand#doAuthorization(). Principal: " + principal + ", Principal class: " + principal.getClass().getName()
+ ", Principal identity: " + System.identityHashCode(principal));
if (principal instanceof WSLCPrincipal) // This code path is hit if this login command handled authentication.
{
ContextManager contextManager = ((WSLCPrincipal) principal).getContextManager();
UserRegistry registry = contextManager.getRegistry(contextManager.getDefaultRealm());
try {
List groups = new ArrayList(registry.getGroupsForUser(principal.getName()));
groups.retainAll(roles);
// if authorization succeeds, set the user's Subject on this invocation context
// so that the rest of the Thread is executed in the context of the appropriate Subject
if (groups.size() > 0)
ContextManagerFactory.getInstance().setCallerSubject(((WSLCPrincipal) principal).getSubject());
return groups.size() > 0;
} catch (Exception e) {
}
} else // This code path is hit if this login command didn't handle authentication.
{
// The Principal was not null, meaning we have a WAS Principal in the current HttpServletRequest.
// Use that for the authorization check.
HttpServletRequest request = FlexContext.getHttpRequest();
for (Iterator iter = roles.iterator(); iter.hasNext(); ) {
if (request.isUserInRole((String) iter.next()))
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
public boolean logout(Principal principal) {
//as long as credentials are nulled since we can't store
//the authenticated user there's nothing to do
return true;
}
private class WSLCPrincipal implements Principal {
private String username;
private ContextManager contextManager;
private Subject subject;
public WSLCPrincipal(String username, ContextManager contextManager, Subject subject) {
this.username = username;
this.contextManager = contextManager;
this.subject = subject;
}
public String getName() {
return username;
}
public ContextManager getContextManager() {
return contextManager;
}
public Subject getSubject() {
return subject;
}
}
/**
* {@inheritDoc}
*/
public Principal convertPrincipal(Principal principal) {
if (principal instanceof WSLCPrincipal) {
// We are good
return principal;
} else {
// we need the converting
ContextManager contextManager = ContextManagerFactory.getInstance();
Subject subject = null;
try {
subject = contextManager.getCallerSubject();
} catch (WSSecurityException e) {
}
if (subject != null) {
return new WSLCPrincipal(principal.getName(), contextManager, subject);
} else
// Just return the old one
return principal;
}
}
}