KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > iiop > csiv2 > SASClientIdentityInterceptor


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.iiop.csiv2;
23
24 /***************************************
25  * *
26  * JBoss: The OpenSource J2EE WebOS *
27  * *
28  * Distributable under LGPL license. *
29  * See terms of license at gnu.org. *
30  * *
31  ***************************************/

32
33 import java.security.Principal JavaDoc;
34
35 import org.omg.CORBA.Any JavaDoc;
36 import org.omg.CORBA.BAD_PARAM JavaDoc;
37 import org.omg.CORBA.CompletionStatus JavaDoc;
38 import org.omg.CORBA.LocalObject JavaDoc;
39 import org.omg.CORBA.MARSHAL JavaDoc;
40 import org.omg.CORBA.NO_PERMISSION JavaDoc;
41 import org.omg.CORBA.ORB JavaDoc;
42 import org.omg.CSI.AuthorizationElement;
43 import org.omg.CSI.EstablishContext;
44 import org.omg.CSI.GSS_NT_ExportedNameHelper;
45 import org.omg.CSI.ITTAnonymous;
46 import org.omg.CSI.IdentityToken;
47 import org.omg.CSI.MTContextError;
48 import org.omg.CSI.SASContextBody;
49 import org.omg.CSI.SASContextBodyHelper;
50 import org.omg.IOP.Codec JavaDoc;
51 import org.omg.IOP.CodecPackage.FormatMismatch JavaDoc;
52 import org.omg.IOP.CodecPackage.InvalidTypeForEncoding JavaDoc;
53 import org.omg.IOP.CodecPackage.TypeMismatch JavaDoc;
54 import org.omg.IOP.ServiceContext JavaDoc;
55 import org.omg.IOP.TaggedComponent JavaDoc;
56 import org.omg.PortableInterceptor.ClientRequestInfo JavaDoc;
57 import org.omg.PortableInterceptor.ClientRequestInterceptor JavaDoc;
58 import org.omg.CSIIOP.CompoundSecMech;
59 import org.omg.CSIIOP.CompoundSecMechList;
60 import org.omg.CSIIOP.CompoundSecMechListHelper;
61 import org.omg.CSIIOP.EstablishTrustInClient;
62 import org.omg.CSIIOP.IdentityAssertion;
63 import org.omg.CSIIOP.TAG_CSI_SEC_MECH_LIST;
64 import org.omg.GSSUP.InitialContextToken;
65 import org.jacorb.orb.MinorCodes;
66 import org.jboss.logging.Logger;
67 import org.jboss.security.SecurityAssociation;
68 import org.jboss.security.RunAsIdentity;
69
70 /**
71  * This implementation of
72  * <code>org.omg.PortableInterceptor.ClientRequestInterceptor</code> inserts
73  * the security attribute service (SAS) context into outgoing IIOP requests
74  * and handles the SAS messages received from the target security service
75  * in the SAS context of incoming IIOP replies.
76  *
77  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
78  * @version $Revision: 37459 $
79  */

80 public class SASClientIdentityInterceptor
81    extends LocalObject JavaDoc
82    implements ClientRequestInterceptor JavaDoc
83 {
84    private static final Logger log =
85       Logger.getLogger(SASClientIdentityInterceptor.class);
86    private static final boolean traceEnabled = log.isTraceEnabled();
87
88
89    // Constants ------------------------------------------------------
90
private static final int sasContextId =
91       org.omg.IOP.SecurityAttributeService.value;
92
93    /*
94     * Pre-built empty tokens
95     */

96    private static final IdentityToken absentIdentityToken;
97    static {
98       absentIdentityToken = new IdentityToken();
99       absentIdentityToken.absent(true);
100    }
101    private static final AuthorizationElement[] noAuthorizationToken = {};
102    private static final byte[] noAuthenticationToken = {};
103
104    // Fields ---------------------------------------------------------
105
private Codec JavaDoc codec;
106
107    /*
108     * Username and password of this server, in case it does not use an
109     * SSL certificate to authenticate itself when acting as a client.
110     */

111    private static final String JavaDoc serverUsername = "j2ee"; // hardcoded (REVISIT!)
112
private static final String JavaDoc serverPassword = "j2ee"; // hardcoded (REVISIT!)
113

114    // Constructor ----------------------------------------------------
115

116    public SASClientIdentityInterceptor(Codec JavaDoc codec)
117    {
118       this.codec = codec;
119    }
120     
121    // Methods -------------------------------------------------------
122

123     
124    // org.omg.PortableInterceptor.Interceptor operations ------------
125

126    public String JavaDoc name()
127    {
128       return "SASClientIdentityInterceptor";
129    }
130
131    public void destroy()
132    {
133       // do nothing
134
}
135     
136    // ClientRequestInterceptor operations ---------------------------
137

138    public void send_request(ClientRequestInfo JavaDoc ri)
139    {
140       try
141       {
142          CompoundSecMech secMech =
143             CSIv2Util.getMatchingSecurityMech(
144                ri,
145                codec,
146                (short)(EstablishTrustInClient.value
147                        + IdentityAssertion.value), /* client supports */
148                (short)0 /* client requires */);
149          if (secMech == null)
150             return;
151
152          if (traceEnabled)
153          {
154             StringBuffer JavaDoc tmp = new StringBuffer JavaDoc();
155             CSIv2Util.toString(secMech, tmp);
156             log.trace(tmp);
157          }
158          // these "null tokens" will be changed if needed
159
IdentityToken identityToken = absentIdentityToken;
160          byte[] encodedAuthenticationToken = noAuthenticationToken;
161
162          if ((secMech.sas_context_mech.target_supports
163               & IdentityAssertion.value) != 0)
164          {
165             // will create identity token
166
Principal JavaDoc p = null;
167             RunAsIdentity runAs = SecurityAssociation.peekRunAsIdentity();
168             if (runAs != null)
169             {
170                // will use run-as identity
171
p = runAs;
172             }
173             else
174             {
175                // will use caller identity
176
p = SecurityAssociation.getPrincipal();
177             }
178
179             if (p != null)
180             {
181                // The name scope needs to be externalized
182
String JavaDoc name = p.getName();
183                if (name.indexOf('@') < 0)
184                   name += "@default"; // hardcoded (REVISIT!)
185
byte[] principalName = name.getBytes("UTF-8");
186                
187                // encode the principal name as mandated by RFC2743
188
byte[] encodedName =
189                   CSIv2Util.encodeGssExportedName(principalName);
190                
191                // encapsulate the encoded name
192
Any JavaDoc any = ORB.init().create_any();
193                byte[] encapsulatedEncodedName = null;
194                GSS_NT_ExportedNameHelper.insert(any, encodedName);
195                try
196                {
197                   encapsulatedEncodedName = codec.encode_value(any);
198                }
199                catch (InvalidTypeForEncoding JavaDoc e)
200                {
201                   throw new RuntimeException JavaDoc("Unexpected exception: " + e);
202                }
203                
204                // create identity token
205
identityToken = new IdentityToken();
206                identityToken.principal_name(encapsulatedEncodedName);
207             }
208             else if ((secMech.sas_context_mech.supported_identity_types
209                       & ITTAnonymous.value) != 0)
210             {
211                // no run-as or caller identity and the target
212
// supports ITTAnonymous: use the anonymous identity
213
identityToken = new IdentityToken();
214                identityToken.anonymous(true);
215             }
216          }
217             
218          if ((secMech.as_context_mech.target_requires
219               & EstablishTrustInClient.value) != 0)
220          {
221             // will create authentication token with the
222
// configured pair serverUsername/serverPassword
223
byte[] encodedTargetName = secMech.as_context_mech.target_name;
224             String JavaDoc name = serverUsername;
225             if (name.indexOf('@') < 0)
226             {
227                byte[] decodedTargetName =
228                   CSIv2Util.decodeGssExportedName(encodedTargetName);
229                String JavaDoc targetName = new String JavaDoc(decodedTargetName, "UTF-8");
230                name += "@" + targetName; // "@default"
231
}
232             byte[] username = name.getBytes("UTF-8");
233             // I don't know why there is not a better way
234
// to go from char[] -> byte[]
235
byte[] password = serverPassword.getBytes("UTF-8");
236             
237             // create authentication token
238
InitialContextToken authenticationToken =
239                new InitialContextToken(username,
240                                        password,
241                                        encodedTargetName);
242             // ASN.1-encode it, as defined in RFC 2743
243
encodedAuthenticationToken =
244                CSIv2Util.encodeInitialContextToken(authenticationToken, codec);
245          }
246
247          if (identityToken != absentIdentityToken
248              || encodedAuthenticationToken != noAuthenticationToken)
249          {
250             // at least one non-null token was created,
251
// create EstablishContext message with it
252
EstablishContext message =
253                new EstablishContext(0, // stateless ctx id
254
noAuthorizationToken,
255                                     identityToken,
256                                     encodedAuthenticationToken);
257             
258             // create SAS context with the EstablishContext message
259
SASContextBody contextBody = new SASContextBody();
260             contextBody.establish_msg(message);
261             
262             // stuff the SAS context into the outgoing request
263
Any JavaDoc any = ORB.init().create_any();
264             SASContextBodyHelper.insert(any, contextBody);
265             ServiceContext JavaDoc sc =
266                new ServiceContext JavaDoc(sasContextId, codec.encode_value(any));
267             ri.add_request_service_context(sc,
268                                            true /*replace existing context*/);
269          }
270       }
271       catch (java.io.UnsupportedEncodingException JavaDoc e)
272       {
273          throw new MARSHAL JavaDoc("Unexpected exception: " + e);
274       }
275       catch (InvalidTypeForEncoding JavaDoc e)
276       {
277          throw new MARSHAL JavaDoc("Unexpected exception: " + e);
278       }
279    }
280
281    public void send_poll(ClientRequestInfo JavaDoc ri)
282    {
283       // do nothing
284
}
285
286    public void receive_reply(ClientRequestInfo JavaDoc ri)
287    {
288       try
289       {
290          ServiceContext JavaDoc sc = ri.get_reply_service_context(sasContextId);
291          Any JavaDoc msg = codec.decode_value(sc.context_data,
292             SASContextBodyHelper.type());
293          SASContextBody contextBody = SASContextBodyHelper.extract(msg);
294
295          // At this point contextBody should contain a
296
// CompleteEstablishContext message, which does not require any
297
// treatment. ContextError messages should arrive via
298
// receive_exception().
299

300          if (traceEnabled)
301             log.trace("receive_reply: got SAS reply, type " +
302                       contextBody.discriminator());
303
304          if (contextBody.discriminator() == MTContextError.value)
305          {
306             // should not happen
307
log.warn("Unexpected ContextError in SAS reply");
308             throw new NO_PERMISSION JavaDoc("Unexpected ContextError in SAS reply",
309                MinorCodes.SAS_CSS_FAILURE,
310                CompletionStatus.COMPLETED_YES);
311          }
312       }
313       catch (BAD_PARAM JavaDoc e)
314       {
315          // no service context with sasContextId: do nothing
316
}
317       catch (FormatMismatch JavaDoc e)
318       {
319          throw new MARSHAL JavaDoc("Could not parse SAS reply: " + e,
320             0,
321             CompletionStatus.COMPLETED_YES);
322       }
323       catch (TypeMismatch JavaDoc e)
324       {
325          throw new MARSHAL JavaDoc("Could not parse SAS reply: " + e,
326             0,
327             CompletionStatus.COMPLETED_YES);
328       }
329    }
330
331    public void receive_exception(ClientRequestInfo JavaDoc ri)
332    {
333       try
334       {
335          ServiceContext JavaDoc sc = ri.get_reply_service_context(sasContextId);
336          Any JavaDoc msg = codec.decode_value(sc.context_data,
337             SASContextBodyHelper.type());
338          SASContextBody contextBody = SASContextBodyHelper.extract(msg);
339
340          // At this point contextBody may contain a either a
341
// CompleteEstablishContext message or a ContextError message.
342
// Neither message requires any treatment. We decoded the context
343
// body just to check that it contains a well-formed message.
344

345          if (traceEnabled)
346             log.trace("receive_exceptpion: got SAS reply, type " +
347                       contextBody.discriminator());
348       }
349       catch (BAD_PARAM JavaDoc e)
350       {
351          // no service context with sasContextId: do nothing
352
}
353       catch (FormatMismatch JavaDoc e)
354       {
355          throw new MARSHAL JavaDoc("Could not parse SAS reply: " + e,
356             MinorCodes.SAS_CSS_FAILURE,
357             CompletionStatus.COMPLETED_MAYBE);
358       }
359       catch (TypeMismatch JavaDoc e)
360       {
361          throw new MARSHAL JavaDoc("Could not parse SAS reply: " + e,
362             MinorCodes.SAS_CSS_FAILURE,
363             CompletionStatus.COMPLETED_MAYBE);
364       }
365    }
366
367    public void receive_other(ClientRequestInfo JavaDoc ri)
368    {
369       // do nothing
370
}
371
372    CompoundSecMech getSecurityMech(ClientRequestInfo JavaDoc ri)
373    {
374       CompoundSecMechList csmList = null;
375       CompoundSecMech securityMech = null;
376       try
377       {
378           TaggedComponent JavaDoc tc = ri.get_effective_component(TAG_CSI_SEC_MECH_LIST.value);
379
380           Any JavaDoc any = codec.decode_value(tc.component_data,
381              CompoundSecMechListHelper.type());
382
383           csmList = CompoundSecMechListHelper.extract(any);
384
385           // at this point you can inspect the fields csmList.stateful
386
// and csmList.mechanism_list. The latter is an array of
387
// org.omg.CSIIOP.CompoundSecMech instances, which in our IORs
388
// has length 1.
389
//
390
// The actual info you want is in csmList.mechanism_list[0].
391
securityMech = csmList.mechanism_list[0];
392       }
393       catch (BAD_PARAM JavaDoc e)
394       {
395           // no component with TAG_CSI_SEC_MECH_LIST was found
396
}
397       catch (org.omg.IOP.CodecPackage.TypeMismatch JavaDoc tm)
398       {
399           // unexpected exception in codec.decode_value
400
}
401       catch (org.omg.IOP.CodecPackage.FormatMismatch JavaDoc tm)
402       {
403           // unexpected exception in codec.decode_value
404
}
405       return securityMech;
406    }
407 }
408
Popular Tags