View Javadoc

1   /**
2    *
3    * Copyright 2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
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  
18  package org.apache.geronimo.security.network.protocol;
19  
20  import org.activeio.AsyncChannel;
21  import org.activeio.FilterAsyncChannel;
22  import org.activeio.Packet;
23  import org.activeio.adapter.PacketOutputStream;
24  import org.activeio.adapter.PacketToInputStream;
25  import org.activeio.packet.AppendedPacket;
26  import org.activeio.packet.ByteArrayPacket;
27  import org.activeio.packet.FilterPacket;
28  import org.apache.geronimo.security.ContextManager;
29  import org.apache.geronimo.security.IdentificationPrincipal;
30  import org.apache.geronimo.security.SubjectId;
31  
32  import javax.security.auth.Subject;
33  import java.io.DataInputStream;
34  import java.io.DataOutputStream;
35  import java.io.IOException;
36  import java.security.AccessController;
37  import java.util.Collection;
38  
39  /**
40   * SubjectCarryingChannel is a FilterAsynchChannel that allows you to send
41   * the subject associated with the current write operation down to the remote
42   * end of the channel.
43   *
44   * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
45   */
46  public class SubjectCarryingChannel extends FilterAsyncChannel {
47  
48      static final byte PASSTHROUGH = (byte) 0x00;
49      static final byte SET_SUBJECT = (byte) 0x01;
50      static final byte CLEAR_SUBJECT = (byte) 0x2;
51  
52      final private ByteArrayPacket header = new ByteArrayPacket(new byte[1 + 8 + 4]);
53  
54      private Subject remoteSubject;
55      private Subject localSubject;
56  
57      private final boolean enableLocalSubjectPublishing;
58      private final boolean enableRemoteSubjectConsumption;
59  
60      public SubjectCarryingChannel(AsyncChannel next) {
61          this(next, true, true);
62      }
63  
64      public SubjectCarryingChannel(AsyncChannel next, boolean enableLocalSubjectPublishing, boolean enableRemoteSubjectConsumption) {
65          super(next);
66          this.enableLocalSubjectPublishing = enableLocalSubjectPublishing;
67          this.enableRemoteSubjectConsumption = enableRemoteSubjectConsumption;
68      }
69  
70      public void write(Packet packet) throws IOException {
71  
72          // Don't add anything to the packet stream if subject writing is not enabled.
73          if (!enableLocalSubjectPublishing) {
74              super.write(packet);
75              return;
76          }
77  
78          Subject subject = Subject.getSubject(AccessController.getContext());
79          if (remoteSubject != subject) {
80              remoteSubject = subject;
81              Collection principals = remoteSubject.getPrincipals(IdentificationPrincipal.class);
82  
83              if (principals.isEmpty()) {
84                  super.write(createClearSubjectPackt());
85              } else {
86                  IdentificationPrincipal principal = (IdentificationPrincipal) principals.iterator().next();
87                  SubjectId subjectId = principal.getId();
88                  super.write(createSubjectPacket(subjectId.getSubjectId(), subjectId.getHash()));
89              }
90  
91          }
92          super.write(createPassthroughPacket(packet));
93      }
94  
95      public class SubjectPacketFilter extends FilterPacket {
96  
97          SubjectPacketFilter(Packet packet) {
98              super(packet);
99          }
100 
101         public Object narrow(Class target) {
102             if (target == SubjectContext.class) {
103                 return new SubjectContext() {
104                     public Subject getSubject() {
105                         return remoteSubject;
106                     }
107                 };
108             }
109             return super.narrow(target);
110         }
111 
112         public Packet filter(Packet packet) {
113             return new SubjectPacketFilter(packet);
114         }
115 
116     }
117 
118     public void onPacket(Packet packet) {
119 
120         // Don't take anything to the packet stream if subject reading is not enabled.
121         if (!enableRemoteSubjectConsumption) {
122             super.onPacket(packet);
123             return;
124         }
125 
126         try {
127             switch (packet.read()) {
128                 case CLEAR_SUBJECT:
129                     localSubject = null;
130                     return;
131                 case SET_SUBJECT:
132                     SubjectId subjectId = extractSubjectId(packet);
133                     localSubject = ContextManager.getRegisteredSubject(subjectId);
134                     return;
135                 case PASSTHROUGH:
136                     super.onPacket(new SubjectPacketFilter(packet));
137             }
138         } catch (IOException e) {
139             super.onPacketError(e);
140         }
141 
142         super.onPacket(packet);
143     }
144 
145     /**
146      */
147     private SubjectId extractSubjectId(Packet packet) throws IOException {
148         DataInputStream is = new DataInputStream(new PacketToInputStream(packet));
149         Long id = new Long(is.readLong());
150         byte hash[] = new byte[is.readInt()];
151         return new SubjectId(id, hash);
152     }
153 
154     private Packet createClearSubjectPackt() {
155         header.clear();
156         header.write(CLEAR_SUBJECT);
157         header.flip();
158         return header;
159     }
160 
161     private Packet createSubjectPacket(Long subjectId, byte[] hash) throws IOException {
162         header.clear();
163         DataOutputStream os = new DataOutputStream(new PacketOutputStream(header));
164         os.writeByte(SET_SUBJECT);
165         os.writeLong(subjectId.longValue());
166         os.writeInt(hash.length);
167         os.close();
168         header.flip();
169         return AppendedPacket.join(header, new ByteArrayPacket(hash));
170     }
171 
172     private Packet createPassthroughPacket(Packet packet) {
173         header.clear();
174         header.write(PASSTHROUGH);
175         header.flip();
176         return AppendedPacket.join(header, packet);
177     }
178 
179     public Subject getLocalSubject() {
180         return localSubject;
181     }
182 
183     public Subject getRemoteSubject() {
184         return remoteSubject;
185     }
186 
187 }