KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.omg.CORBA.Any JavaDoc;
34 import org.omg.CORBA.BAD_PARAM JavaDoc;
35 import org.omg.CORBA.MARSHAL JavaDoc;
36 import org.omg.CORBA.NO_PERMISSION JavaDoc;
37 import org.omg.CORBA.LocalObject JavaDoc;
38 import org.omg.CORBA.ORB JavaDoc;
39 import org.omg.CSI.CompleteEstablishContext;
40 import org.omg.CSI.ContextError;
41 import org.omg.CSI.EstablishContext;
42 import org.omg.CSI.GSS_NT_ExportedNameHelper;
43 import org.omg.CSI.ITTPrincipalName;
44 import org.omg.CSI.IdentityToken;
45 import org.omg.CSI.MTEstablishContext;
46 import org.omg.CSI.MTMessageInContext;
47 import org.omg.CSI.SASContextBody;
48 import org.omg.CSI.SASContextBodyHelper;
49 import org.omg.GSSUP.ErrorToken;
50 import org.omg.GSSUP.ErrorTokenHelper;
51 import org.omg.GSSUP.GSS_UP_S_G_UNSPECIFIED;
52 import org.omg.GSSUP.InitialContextToken;
53 import org.omg.IOP.Codec JavaDoc;
54 import org.omg.IOP.CodecPackage.FormatMismatch JavaDoc;
55 import org.omg.IOP.CodecPackage.TypeMismatch JavaDoc;
56 import org.omg.IOP.CodecPackage.InvalidTypeForEncoding JavaDoc;
57 import org.omg.IOP.ServiceContext JavaDoc;
58 import org.omg.PortableInterceptor.ServerRequestInfo JavaDoc;
59 import org.omg.PortableInterceptor.ServerRequestInterceptor JavaDoc;
60
61 import org.jboss.iiop.CorbaORBService;
62 import org.jboss.logging.Logger;
63
64 /**
65  * This implementation of
66  * <code>org.omg.PortableInterceptor.ServerRequestInterceptor</code>
67  * extracts the security attribute service (SAS) context from incoming IIOP
68  * and inserts SAS messages into the SAS context of outgoing IIOP replies.
69  *
70  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
71  * @version $Revision: 37459 $
72  */

73 public class SASTargetInterceptor
74       extends LocalObject JavaDoc
75       implements ServerRequestInterceptor JavaDoc
76 {
77
78    // Static fields and initializers ---------------------------------
79

80    private static final Logger log =
81       Logger.getLogger(SASTargetInterceptor.class);
82    private static final boolean traceEnabled = log.isTraceEnabled();
83
84    private static final int sasContextId =
85       org.omg.IOP.SecurityAttributeService.value;
86    
87    private static final byte[] empty = new byte[0];
88    private static final IdentityToken absent;
89    
90    /** Scratch field for <code>CompleteEstablishContext<code> messages */
91    private static final SASContextBody msgBodyCtxAccepted;
92    
93    /** Ready-to-go <code>CompleteEstablishContext<code> message
94        with context id set to zero */

95    private static final Any JavaDoc msgCtx0Accepted;
96    
97    static
98    {
99       // initialize absent
100
absent = new IdentityToken();
101       absent.absent(true);
102       
103       // initialize msgBodyCtxAccepted
104
// (Note that "context stateful" is always set to false. Even if the
105
// client wants a stateful context, we negotiate the context down to
106
// stateless.)
107
CompleteEstablishContext ctxAccepted =
108          new CompleteEstablishContext(0, /* context id */
109                                       false, /* context stateful */
110                                       new byte[0] /* no final token */);
111       
112       msgBodyCtxAccepted = new SASContextBody();
113       msgBodyCtxAccepted.complete_msg(ctxAccepted);
114       
115       // initialize msgCtx0Accepted
116
msgCtx0Accepted = createMsgCtxAccepted(0);
117    }
118    
119    // Static methods ------------------------------------------------
120

121    private static Any JavaDoc createMsgCtxAccepted(long contextId)
122    {
123       Any JavaDoc any = ORB.init().create_any();
124       synchronized (msgBodyCtxAccepted)
125       {
126          msgBodyCtxAccepted.complete_msg().client_context_id = contextId;
127          SASContextBodyHelper.insert(any, msgBodyCtxAccepted);
128       }
129       return any;
130    }
131    
132    // Fields ---------------------------------------------------------
133

134    private final Codec JavaDoc codec;
135    
136    /** Scratch field for <code>ContextError<code> messages */
137    private final SASContextBody msgBodyCtxError;
138    
139    /** Ready-to-go <code>ContextError<code> message with context id set to
140        zero and major status "invalid evidence" */

141    private final Any JavaDoc msgCtx0Rejected;
142    
143    private ThreadLocal JavaDoc threadLocalData = new ThreadLocal JavaDoc() {
144          protected synchronized Object JavaDoc initialValue()
145          {
146             return new CurrentRequestInfo(); // see nested class below
147
}
148       };
149    
150    // Nested class -------------------------------------------------
151

152    /**
153     * The <code>CurrentRequestInfo</code> class holds SAS information
154     * associated with IIOP request handled by the current thread.
155     */

156    private static class CurrentRequestInfo
157    {
158       boolean sasContextReceived;
159       boolean authenticationTokenReceived;
160       byte[] incomingUsername;
161       byte[] incomingPassword;
162       byte[] incomingTargetName;
163       IdentityToken incomingIdentity;
164       byte[] incomingPrincipalName;
165       long contextId;
166       Any JavaDoc sasReply;
167       boolean sasReplyIsAccept; // true if sasReply is
168
// CompleteEstablishContext (for
169
// interoperability with IONA's ASP 6.0)
170
CurrentRequestInfo()
171       {
172       }
173    }
174    
175    // Private method ------------------------------------------------
176

177    private Any JavaDoc createMsgCtxError(long contextId, int majorStatus)
178    {
179       Any JavaDoc any = ORB.init().create_any();
180       synchronized (msgBodyCtxError)
181       {
182          msgBodyCtxError.error_msg().client_context_id = contextId;
183          msgBodyCtxError.error_msg().major_status = majorStatus;
184          SASContextBodyHelper.insert(any, msgBodyCtxError);
185       }
186       return any;
187    }
188
189    // Constructor ---------------------------------------------------
190

191    public SASTargetInterceptor(Codec JavaDoc codec)
192    {
193       this.codec = codec;
194       
195       // build encapsulated GSSUP error token for ContextError messages
196
// (the error code within the error token is GSS_UP_S_G_UNSPECIFIED,
197
// which says nothing about the cause of the error)
198
ErrorToken errorToken = new ErrorToken(GSS_UP_S_G_UNSPECIFIED.value);
199       Any JavaDoc any = ORB.init().create_any();
200       byte[] encapsulatedErrorToken;
201       
202       ErrorTokenHelper.insert(any, errorToken);
203       try
204       {
205          encapsulatedErrorToken = codec.encode_value(any);
206       }
207       catch (InvalidTypeForEncoding JavaDoc e)
208       {
209          throw new RuntimeException JavaDoc("Unexpected exception: " + e);
210       }
211       
212       // initialize msgBodyCtxError
213
ContextError ctxError =
214          new ContextError(0, /* context id */
215                           1, /* major status: invalid evidence */
216                           1, /* minor status (always 1) */
217                           encapsulatedErrorToken);
218       
219       msgBodyCtxError = new SASContextBody();
220       msgBodyCtxError.error_msg(ctxError);
221       
222       // initialize msgCtx0Rejected (major status: invalid evidence)
223
msgCtx0Rejected = createMsgCtxError(0, 1);
224       
225    }
226     
227    // Methods -------------------------------------------------------
228

229    /**
230     * Returns true if an SAS context arrived with the current IIOP request.
231     */

232    boolean sasContextReceived()
233    {
234       CurrentRequestInfo threadLocal =
235             (CurrentRequestInfo)threadLocalData.get();
236       return threadLocal.sasContextReceived;
237    }
238    
239    /**
240     * Returns true if a client authentication token arrived with the
241     * current IIOP request.
242     */

243    boolean authenticationTokenReceived()
244    {
245       CurrentRequestInfo threadLocal =
246          (CurrentRequestInfo)threadLocalData.get();
247       return threadLocal.authenticationTokenReceived;
248    }
249    
250    /**
251     * Returns the username that arrived in the current IIOP request.
252     */

253    byte[] getIncomingUsername()
254    {
255       CurrentRequestInfo threadLocal =
256             (CurrentRequestInfo)threadLocalData.get();
257       return threadLocal.incomingUsername;
258    }
259    
260    /**
261     * Returns the password that arrived in the current IIOP request.
262     */

263    byte[] getIncomingPassword()
264    {
265       CurrentRequestInfo threadLocal =
266             (CurrentRequestInfo)threadLocalData.get();
267       return threadLocal.incomingPassword;
268    }
269    
270    /**
271     * Returns the target name that arrived in the current IIOP request.
272     */

273    byte[] getIncomingTargetName()
274    {
275       CurrentRequestInfo threadLocal =
276             (CurrentRequestInfo)threadLocalData.get();
277       return threadLocal.incomingTargetName;
278    }
279    
280    /**
281     * Returns the <code>org.omg.CSI.IdentityToken<code> that arrived in
282     * the current IIOP request.
283     */

284    IdentityToken getIncomingIdentity()
285    {
286       CurrentRequestInfo threadLocal =
287             (CurrentRequestInfo)threadLocalData.get();
288       return threadLocal.incomingIdentity;
289    }
290
291    /**
292     * Returns the principal name that arrived in the current IIOP request.
293     */

294    byte[] getIncomingPrincipalName()
295    {
296       CurrentRequestInfo threadLocal =
297             (CurrentRequestInfo)threadLocalData.get();
298       return threadLocal.incomingPrincipalName;
299    }
300    
301    /**
302     * Sets the outgoing SAS reply to <code>ContextError</code>, with major
303     * status "invalid evidence".
304     */

305    void rejectIncomingContext()
306    {
307       CurrentRequestInfo threadLocal =
308          (CurrentRequestInfo)threadLocalData.get();
309       
310       if (threadLocal.sasContextReceived)
311       {
312          threadLocal.sasReply =
313             (threadLocal.contextId == 0)
314             ? msgCtx0Rejected
315             : createMsgCtxError(threadLocal.contextId,
316                                 1 /* major status: invalid evidence */);
317          threadLocal.sasReplyIsAccept = false;
318       }
319    }
320    
321    // org.omg.PortableInterceptor.Interceptor operations ------------
322

323    public String JavaDoc name()
324    {
325       return "SASTargetInterceptor";
326    }
327    
328    public void destroy()
329    {
330       // do nothing
331
}
332    
333    // ServerRequestInterceptor operations ---------------------------
334

335    public void receive_request_service_contexts(ServerRequestInfo JavaDoc ri)
336    {
337       // do nothing
338
}
339    
340    // ServerRequestInterceptor operations ---------------------------
341

342    public void receive_request(ServerRequestInfo JavaDoc ri)
343    {
344       if (traceEnabled)
345          log.trace("receive_request " + ri.operation());
346       CurrentRequestInfo threadLocal =
347             (CurrentRequestInfo)threadLocalData.get();
348       
349       threadLocal.sasContextReceived = false;
350       threadLocal.authenticationTokenReceived = false;
351       threadLocal.incomingUsername = empty;
352       threadLocal.incomingPassword = empty;
353       threadLocal.incomingTargetName = empty;
354       threadLocal.incomingIdentity = absent;
355       threadLocal.incomingPrincipalName = empty;
356       threadLocal.sasReply = null;
357       threadLocal.sasReplyIsAccept = false;
358       
359       try
360       {
361          ServiceContext JavaDoc sc = ri.get_request_service_context(sasContextId);
362          Any JavaDoc any = codec.decode_value(sc.context_data,
363                                       SASContextBodyHelper.type());
364          SASContextBody contextBody = SASContextBodyHelper.extract(any);
365          
366          if (contextBody == null)
367          {
368             // we're done
369
return;
370          }
371          else if (contextBody.discriminator() == MTMessageInContext.value)
372          {
373             // should not happen, as stateful context requests are always
374
// negotiated down to stateless in this implementation
375
long contextId =
376                contextBody.in_context_msg().client_context_id;
377             threadLocal.sasReply =
378                createMsgCtxError(contextId,
379                                  4 /* major status: no context */);
380             throw new NO_PERMISSION JavaDoc("SAS context does not exist.");
381          }
382          else if (contextBody.discriminator() == MTEstablishContext.value)
383          {
384             EstablishContext message = contextBody.establish_msg();
385             threadLocal.contextId = message.client_context_id;
386             threadLocal.sasContextReceived = true;
387             
388             if (message.client_authentication_token != null
389                 && message.client_authentication_token.length > 0)
390             {
391                if (traceEnabled)
392                   log.trace("received client authentication token");
393                InitialContextToken authToken =
394                   CSIv2Util.decodeInitialContextToken(
395                                           message.client_authentication_token,
396                                           codec);
397                if (authToken == null)
398                {
399                   threadLocal.sasReply =
400                      createMsgCtxError(message.client_context_id,
401                                        2 /* major status:
402                                             invalid mechanism */
);
403                   throw new NO_PERMISSION JavaDoc("Could not decode " +
404                                           "initial context token.");
405                }
406                threadLocal.incomingUsername = authToken.username;
407                threadLocal.incomingPassword = authToken.password;
408                threadLocal.incomingTargetName =
409                   CSIv2Util.decodeGssExportedName(authToken.target_name);
410                if (threadLocal.incomingTargetName == null)
411                {
412                   threadLocal.sasReply =
413                      createMsgCtxError(message.client_context_id,
414                                        2 /* major status:
415                                             invalid mechanism */
);
416                   throw new NO_PERMISSION JavaDoc("Could not decode target name " +
417                                           "in initial context token.");
418                }
419                
420                
421                threadLocal.authenticationTokenReceived = true;
422             }
423             if (message.identity_token != null)
424             {
425                if (traceEnabled)
426                   log.trace("received identity token");
427                threadLocal.incomingIdentity = message.identity_token;
428                if (message.identity_token.discriminator() == ITTPrincipalName.value)
429                {
430                   // Extract the RFC2743-encoded name
431
// from CDR encapsulation
432
Any JavaDoc a = codec.decode_value(
433                                        message.identity_token.principal_name(),
434                                        GSS_NT_ExportedNameHelper.type());
435                   byte[] encodedName = GSS_NT_ExportedNameHelper.extract(a);
436                   
437                   // Decode the principal name
438
threadLocal.incomingPrincipalName =
439                      CSIv2Util.decodeGssExportedName(encodedName);
440                   
441                   if (threadLocal.incomingPrincipalName == null)
442                   {
443                      threadLocal.sasReply =
444                         createMsgCtxError(message.client_context_id,
445                                           2 /* major status:
446                                                invalid mechanism */
);
447                      throw new NO_PERMISSION JavaDoc("Could not decode " +
448                                              "incoming principal name.");
449                   }
450                }
451             }
452             threadLocal.sasReply = (threadLocal.contextId == 0) ?
453                                    msgCtx0Accepted :
454                                    createMsgCtxAccepted(threadLocal.contextId);
455             threadLocal.sasReplyIsAccept = true;
456          }
457       }
458       catch (BAD_PARAM JavaDoc e)
459       {
460          // no service context with sasContextId: do nothing
461
}
462       catch (FormatMismatch JavaDoc e)
463       {
464          throw new MARSHAL JavaDoc("Exception decoding context data in " +
465                            "SASTargetInterceptor: " + e);
466       }
467       catch (TypeMismatch JavaDoc e)
468       {
469          throw new MARSHAL JavaDoc("Exception decoding context data in " +
470                            "SASTargetInterceptor: " + e);
471       }
472    }
473     
474    public void send_reply(ServerRequestInfo JavaDoc ri)
475    {
476       if (traceEnabled)
477          log.trace("send_reply " + ri.operation());
478       CurrentRequestInfo threadLocal =
479          (CurrentRequestInfo)threadLocalData.get();
480       
481       if (threadLocal.sasReply != null)
482       {
483             try
484             {
485                ServiceContext JavaDoc sc =
486                   new ServiceContext JavaDoc(sasContextId,
487                                      codec.encode_value(threadLocal.sasReply));
488                ri.add_reply_service_context(sc, true);
489             }
490             catch (InvalidTypeForEncoding JavaDoc e)
491             {
492                throw new MARSHAL JavaDoc("Unexpected exception: " + e);
493             }
494       }
495    }
496    
497    public void send_exception(ServerRequestInfo JavaDoc ri)
498    {
499       if (traceEnabled)
500          log.trace("send_exception " + ri.operation() + ": ");
501       CurrentRequestInfo threadLocal =
502             (CurrentRequestInfo)threadLocalData.get();
503
504       // The check for sasReplyIsAccept below was added for interoperability
505
// with IONA's ASP 6.0, which throws an ArrayIndexOutOfBoundsException
506
// when it receives an IIOP reply carrying both an application exception
507
// and a SAS reply CompleteEstablishContext. The sasReplyIsAccept flag
508
// serves the purpose of refraining from sending an SAS accept
509
// (CompleteEstablishContext) reply together with an exception.
510
//
511
// The CSIv2 spec does not explicitly disallow an SAS accept in an
512
// IIOP exception reply.
513
//
514
if (threadLocal.sasReply != null &&
515           (!threadLocal.sasReplyIsAccept ||
516            CorbaORBService.getSendSASAcceptWithExceptionEnabledFlag() == true))
517       {
518          try
519          {
520             ServiceContext JavaDoc sc =
521                new ServiceContext JavaDoc(sasContextId,
522                                   codec.encode_value(threadLocal.sasReply));
523             ri.add_reply_service_context(sc, true);
524          }
525          catch (InvalidTypeForEncoding JavaDoc e)
526          {
527             throw new MARSHAL JavaDoc("Unexpected exception: " + e);
528          }
529       }
530    }
531    
532    public void send_other(ServerRequestInfo JavaDoc ri)
533    {
534       // Do nothing. According to the SAS spec, LOCATION_FORWARD reply
535
// carries no SAS message.
536
}
537 }
538
Popular Tags