blob: e1389427c818c283df2119ea3bc986e6a1c362d6 [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);
}
}
}