blob: 0f698c89399a279eae75f21ed5b800d74f369e4e [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 java.security.Principal;
import java.util.Iterator;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import weblogic.security.SimpleCallbackHandler;
import weblogic.security.SubjectUtils;
import weblogic.security.services.Authentication;
import weblogic.servlet.security.ServletAuthentication;
import weblogic.security.Security;
import flex.messaging.FlexContext;
/**
* Authenticates against WebLogic and if using an HttpServlet will store
* the authenticated user in the request.
*/
public class WeblogicLoginCommand extends AppServerLoginCommand implements PrincipalConverter
{
/** {@inheritDoc} */
public Principal doAuthentication(String username, Object credentials)
{
Principal principal = null;
String password = extractPassword(credentials);
if (password != null)
{
// Test for the presence of a response here (rather than request) because NIO
// endpoints require the alternate code path and they don't populate the response
// in FlexContext.
HttpServletResponse response = FlexContext.getHttpResponse();
if (response != null)
{
HttpServletRequest request = FlexContext.getHttpRequest();
int result = ServletAuthentication.FAILED_AUTHENTICATION;
try
{
result = ServletAuthentication.login(username, password,
request);
}
catch (LoginException e)
{
}
catch (NoSuchMethodError noSuchMethodError)
{
//even though we're not supporting WebLogic 7 anymore...
// Weblogic 7.0.4 didn't have login(), so try weak().
result = ServletAuthentication.weak(username, password,
request);
}
if (result != ServletAuthentication.FAILED_AUTHENTICATION)
{
// To authorize against the Groups defined via the WL console, we need
// to have a SubjectPrincipal. Because we do not need a principal to authorize
// against web.xml / weblogic.xml, always save the SubjectPrincipal
principal = getSubjectPrincipal(username, password);
}
}
else // Code path for NIO endpoints.
{
principal = getSubjectPrincipal(username, password);
}
}
return principal;
}
/**
* Get a SubjectPrincipal for the current user.
* @return the generated SubjectPrincipal
*/
private Principal getSubjectPrincipal(String username, String password)
{
Principal principal=null;
SimpleCallbackHandler handler =
new SimpleCallbackHandler(username, password);
try
{
Subject subject = Authentication.login(handler);
principal = new SubjectPrincipal(subject);
}
catch (LoginException e)
{
// let authentication fail if this fails
}
return principal;
}
/**
* Authorize a user against the Groups defined in the WL console.
* @param principal - Current user principal
* @param roles - Set of roles that allow a succesfull authorization
* @return true if the authorization were succesfull
*/
private boolean doSubjectGroupAuthorization(Principal principal, List roles)
{
boolean authorized = false;
Subject subject = null;
if (principal instanceof SubjectPrincipal)
{
subject = ((SubjectPrincipal)principal).getSubject();
}
else
{
subject = Security.getCurrentSubject();
}
if (subject == null)
{
return false;
}
Iterator iter = roles.iterator();
while (iter.hasNext())
{
String role = (String)iter.next();
if (SubjectUtils.isUserInGroup(subject, role))
{
authorized = true;
break;
}
}
return authorized;
}
/** {@inheritDoc} */
public boolean doAuthorization(Principal principal, List roles)
{
if (principal == null)
return false; // Avoid NPEs.
//NOTE: I believe that both HttpServletRequest.isUserInRole and
//SubjectUtils.isUserInGroup returns if the user is in a Weblogic Group,
//not necessarily the Weblogic role construct
boolean authorized = false;
// Test for the presence of a response here (rather than request) because NIO
// endpoints require the alternate code path and they don't populate the response
// in FlexContext.
HttpServletResponse response = FlexContext.getHttpResponse();
if (response != null)
{
HttpServletRequest request = FlexContext.getHttpRequest();
// This will attempt to authorize the user against roles configured
// in web.xml and weblogic.xml.
authorized = doAuthorization(principal, roles, request);
// We also want to support roles defined via the WL console
// attempt this authorization here
if (!authorized)
{
authorized = doSubjectGroupAuthorization(principal, roles);
}
}
else // Code path for NIO endpoints.
{
authorized = doSubjectGroupAuthorization(principal, roles);
}
return authorized;
}
/** {@inheritDoc} */
public boolean logout(Principal principal)
{
HttpServletResponse response = FlexContext.getHttpResponse();
if (response != null)
{
// Destroy the Principal maintained by the app server.
HttpServletRequest request = FlexContext.getHttpRequest();
ServletAuthentication.logout(request);
}
// else, current non-servlet session will be automatically invalidated, destroying any active Principal.
return true;
}
private class SubjectPrincipal implements Principal
{
private Subject subject;
public SubjectPrincipal(Subject subject)
{
this.subject = subject;
}
public String getName()
{
return SubjectUtils.getUserPrincipal(subject).getName();
}
public Subject getSubject()
{
return subject;
}
}
/** {@inheritDoc} */
public Principal convertPrincipal(Principal principal)
{
if (principal instanceof SubjectPrincipal)
{
return principal;
}
else
{
// We need to do the converting
Subject subject = Security.getCurrentSubject();
return new SubjectPrincipal(subject);
}
}
}