View Javadoc
1   /*
2    * JBoss, Home of Professional Open Source
3    * Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual
4    * contributors by the @authors tag. See the copyright.txt in the
5    * distribution for a full listing of individual contributors.
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * http://www.apache.org/licenses/LICENSE-2.0
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.jboss.as.quickstarts.ejb_security_interceptors;
18  
19  import java.security.Principal;
20  import java.util.Collection;
21  import java.util.Map;
22  
23  import javax.ejb.EJBAccessException;
24  import javax.interceptor.AroundInvoke;
25  import javax.interceptor.InvocationContext;
26  
27  import org.jboss.as.core.security.api.UserPrincipal;
28  import org.jboss.as.security.api.ContextStateCache;
29  import org.jboss.logging.Logger;
30  
31  /**
32   * The server side security interceptor responsible for handling any security identity propagated from the client.
33   *
34   * @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
35   */
36  public class ServerSecurityInterceptor {
37  
38      private static final Logger logger = Logger.getLogger(ServerSecurityInterceptor.class);
39  
40      static final String DELEGATED_USER_KEY = ServerSecurityInterceptor.class.getName() + ".DelegationUser";
41  
42      @AroundInvoke
43      public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {
44          Principal desiredUser = null;
45          UserPrincipal connectionUser = null;
46  
47          Map<String, Object> contextData = invocationContext.getContextData();
48          if (contextData.containsKey(DELEGATED_USER_KEY)) {
49  
50              desiredUser = new SimplePrincipal((String) contextData.get(DELEGATED_USER_KEY));
51  
52              Collection<Principal> connectionPrincipals = SecurityActions.getConnectionPrincipals();
53  
54              if (connectionPrincipals != null) {
55                  for (Principal current : connectionPrincipals) {
56                      if (current instanceof UserPrincipal) {
57                          connectionUser = (UserPrincipal) current;
58                          break;
59                      }
60                  }
61  
62              } else {
63                  throw new IllegalStateException("Delegation user requested but no user on connection found.");
64              }
65          }
66  
67  
68          ContextStateCache stateCache = null;
69          try {
70              if (desiredUser != null && connectionUser != null
71                  && (desiredUser.getName().equals(connectionUser.getName()) == false)) {
72                  // The final part of this check is to verify that the change does actually indicate a change in user.
73                  try {
74                      // We have been requested to use an authentication token
75                      // so now we attempt the switch.
76                      stateCache = SecurityActions.pushIdentity(desiredUser, new OuterUserCredential(connectionUser));
77                  } catch (Exception e) {
78                      logger.error("Failed to switch security context for user", e);
79                      // Don't propagate the exception stacktrace back to the client for security reasons
80                      throw new EJBAccessException("Unable to attempt switching of user.");
81                  }
82              }
83  
84              return invocationContext.proceed();
85          } finally {
86              // switch back to original context
87              if (stateCache != null) {
88                  SecurityActions.popIdentity(stateCache);;
89              }
90          }
91      }
92  
93      private static class SimplePrincipal implements Principal {
94  
95          private final String name;
96  
97          private SimplePrincipal(final String name) {
98              if (name == null) {
99                  throw new IllegalArgumentException("name can not be null.");
100             }
101             this.name = name;
102         }
103 
104         public String getName() {
105             return name;
106         }
107 
108         @Override
109         public int hashCode() {
110             return name.hashCode();
111         }
112 
113         @Override
114         public boolean equals(Object other) {
115             return other instanceof SimplePrincipal && equals((SimplePrincipal) other);
116         }
117 
118         public boolean equals(SimplePrincipal other) {
119             return this == other || other != null && name.equals(other.name);
120         }
121 
122     }
123 }