001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.connector.outbound;
019
020 import javax.resource.ResourceException;
021 import javax.resource.spi.ApplicationServerInternalException;
022 import javax.security.auth.Subject;
023
024 /**
025 * SubjectInterceptor.java This is installed only when the plan includes a container-managed-security element.
026 *
027 *
028 * Created: Mon Oct 6 14:31:56 2003
029 *
030 * @version $Rev: 559235 $ $Date: 2007-07-24 18:01:59 -0400 (Tue, 24 Jul 2007) $
031 */
032 public class SubjectInterceptor implements ConnectionInterceptor {
033
034 private final ConnectionInterceptor next;
035 private final SubjectSource subjectSource;
036
037 public SubjectInterceptor(final ConnectionInterceptor next, final SubjectSource subjectSource) {
038 this.next = next;
039 this.subjectSource = subjectSource;
040 }
041
042 public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
043 Subject currentSubject = null;
044 if (!connectionInfo.isApplicationManagedSecurity()) {
045 try {
046 currentSubject = subjectSource.getSubject();
047 } catch (SecurityException e) {
048 throw new ResourceException("Can not obtain Subject for login", e);
049 }
050 if (currentSubject == null) {
051 throw new ResourceException("No subject for container managed security");
052 }
053 }
054 ManagedConnectionInfo originalManagedConnectionInfo = connectionInfo.getManagedConnectionInfo();
055 //No existing managed connection, get an appropriate one and return.
056 if (originalManagedConnectionInfo.getManagedConnection() == null) {
057 originalManagedConnectionInfo.setSubject(currentSubject);
058 next.getConnection(connectionInfo);
059 } else {
060 Subject oldSubject = originalManagedConnectionInfo.getSubject();
061 if (currentSubject == null ? oldSubject != null : !currentSubject.equals(oldSubject)) {
062 if (connectionInfo.isUnshareable()) {
063 throw new ApplicationServerInternalException("Unshareable resource is attempting to change security context: expected request under: " + oldSubject + ", received request under: " + currentSubject);
064 } else {
065 //existing managed connection, wrong subject: must re-associate.
066 //make a ConnectionInfo to process removing the handle from the old mc
067 ConnectionInfo returningConnectionInfo = new ConnectionInfo();
068 returningConnectionInfo.setManagedConnectionInfo(originalManagedConnectionInfo);
069 //This should decrement handle count, but not close the handle, when returnConnection is called
070 //I'm not sure how to test/assure this.
071 returningConnectionInfo.setConnectionHandle(connectionInfo.getConnectionHandle());
072
073 //make a new ManagedConnectionInfo for the mc we will ask for
074 ManagedConnectionInfo newManagedConnectionInfo =
075 new ManagedConnectionInfo(
076 originalManagedConnectionInfo.getManagedConnectionFactory(),
077 originalManagedConnectionInfo.getConnectionRequestInfo());
078 newManagedConnectionInfo.setSubject(currentSubject);
079 connectionInfo.setManagedConnectionInfo(newManagedConnectionInfo);
080 next.getConnection(connectionInfo);
081 //process the removal of the handle from the previous mc
082 returnConnection(returningConnectionInfo, ConnectionReturnAction.RETURN_HANDLE);
083 }
084 } else {
085 //otherwise, the current ManagedConnection matches the security info, we keep it.
086 //set up the tx context
087 next.getConnection(connectionInfo);
088 }
089 }
090 }
091
092 public void returnConnection(
093 ConnectionInfo connectionInfo,
094 ConnectionReturnAction connectionReturnAction) {
095 next.returnConnection(connectionInfo, connectionReturnAction);
096 }
097
098 public void destroy() {
099 next.destroy();
100 }
101
102 }