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
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
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 }