| /* |
| * 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); |
| } |
| } |
| } |