KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > iiop > security > SecServerRequestInterceptor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.iiop.security;
25
26 /**
27  * This class is a server side request interceptor for CSIV2.
28  * It is used to send and receive the service context in a
29  * a service context element in the service context list in
30  * an IIOP header.
31  *
32  * @author: Sekhar Vajjhala
33  * @author: Harpreet Singh
34  * @author: Shing Wai Chan
35  */

36
37 import org.omg.CORBA.*;
38 import org.omg.PortableInterceptor.*;
39 import org.omg.IOP.*;
40
41 import java.util.*;
42 import java.security.cert.X509Certificate JavaDoc;
43
44 /* Import classes generated from CSIV2 idl files */
45 import com.sun.corba.ee.org.omg.CSI.*;
46 import com.sun.corba.ee.org.omg.GSSUP.*;
47
48 /* Import classes required for DER encoding and decoding */
49 import sun.security.util.DerInputStream;
50 import sun.security.util.DerOutputStream;
51 import sun.security.util.DerValue;
52
53 import sun.security.x509.*; // for X500 DN names
54
import javax.security.auth.*; // for JAAS subject
55

56 import com.sun.enterprise.security.auth.login.PasswordCredential;
57 import com.sun.enterprise.security.auth.login.X509CertificateCredential;
58 import com.sun.enterprise.util.ORBManager;
59 import com.sun.enterprise.util.LocalStringManagerImpl;
60 import com.sun.enterprise.log.Log;
61 import java.util.logging.*;
62 import com.sun.logging.*;
63 /*
64  * Security server request interceptor
65  */

66
67 public class SecServerRequestInterceptor
68     extends org.omg.CORBA.LocalObject JavaDoc
69     implements ServerRequestInterceptor
70 {
71
72     private static java.util.logging.Logger JavaDoc _logger=null;
73     static{
74        _logger=LogDomains.getLogger(LogDomains.CORBA_LOGGER);
75         }
76     private static LocalStringManagerImpl localStrings =
77         new LocalStringManagerImpl(SecServerRequestInterceptor.class);
78     private InheritableThreadLocal JavaDoc counterForCalls = new InheritableThreadLocal JavaDoc();
79
80     /**
81      * Hard code the value of 15 for SecurityAttributeService until
82      * it is defined in IOP.idl.
83      * sc.context_id = SecurityAttributeService.value;
84      */

85     protected static final int SECURITY_ATTRIBUTE_SERVICE_ID = 15;
86     // the major and minor codes for a invalid mechanism
87
private static final int INVALID_MECHANISM_MAJOR = 2;
88     private static final int INVALID_MECHANISM_MINOR = 1;
89
90     /* used when inserting into service context field */
91     private static final boolean NO_REPLACE = false;
92
93     /* name of interceptor used for logging purposes (name + "::") */
94     private String JavaDoc prname;
95     private String JavaDoc name;
96     private Codec codec;
97     private ORB orb;
98     SecurityService secsvc = null; // Security Service
99

100
101     public SecServerRequestInterceptor( String JavaDoc name, Codec codec) {
102         this.name = name;
103         this.codec = codec;
104         this.prname = name + "::";
105     }
106
107     public String JavaDoc name() {
108         return name;
109     }
110
111     /**
112      * Create a ContextError message. This is currently designed to work only
113      * for the GSSUP mechanism.
114      */

115
116     /* Create a ContexError Message */
117     private SASContextBody createContextError(int status) {
118         /**
119          * CSIV2 SPEC NOTE:
120          *
121          * Check that CSIV2 spec does not require an error token to be sent
122          * for the GSSUP mechanism.
123          */

124
125         return createContextError(1, status);
126     }
127
128     /* create a context error with the specified major and minor status
129      */

130     private SASContextBody createContextError(int major, int minor) {
131         
132         if(_logger.isLoggable(Level.FINE)) {
133             _logger.log(Level.FINE,"Creating ContextError message: major code = "+ major+ "minor code= "+ minor);
134         }
135         byte error_token[] = {} ;
136         ContextError ce = new ContextError(0, /* stateless client id */
137                                            major, // major
138
minor, // minor
139
error_token);
140         SASContextBody sasctxtbody = new SASContextBody();
141         sasctxtbody.error_msg(ce);
142         return sasctxtbody;
143     }
144
145     /**
146      * Create a CompleteEstablishContext Message. This currently works only
147      * for the GSSUP mechanism.
148      */

149     private SASContextBody createCompleteEstablishContext(int status) {
150         /**
151          * CSIV2 SPEC NOTE:
152          *
153          * Check CSIV2 spec to make sure that there is no
154          * final_context_token for GSSUP mechanism
155          */

156         if(_logger.isLoggable(Level.FINE)){
157             _logger.log(Level.FINE,"Creating CompleteEstablishContext message");
158         }
159         byte[] final_context_token = {} ;
160         CompleteEstablishContext cec = new CompleteEstablishContext(
161                               0, // stateless client id
162
false, // for stateless
163
final_context_token);
164         SASContextBody sasctxtbody = new SASContextBody();
165         sasctxtbody.complete_msg(cec);
166         return sasctxtbody;
167     }
168
169     /**
170      * CDR encode a SAS Context body and then construct a service context
171      * element.
172      */

173     private ServiceContext createSvcContext(SASContextBody sasctxtbody) {
174
175         ServiceContext sc = null;
176
177         Any a = orb.create_any();
178         SASContextBodyHelper.insert(a, sasctxtbody);
179
180         byte[] cdr_encoded_saselm = {};
181         try {
182             cdr_encoded_saselm = codec.encode_value(a);
183         } catch (Exception JavaDoc e) {
184                 _logger.log(Level.SEVERE,"iiop.encode_exception",e);
185         }
186         sc = new ServiceContext();
187         sc.context_id = SECURITY_ATTRIBUTE_SERVICE_ID;
188         sc.context_data = cdr_encoded_saselm;
189         return sc;
190
191     }
192
193     /**
194      * Create an identity from an Identity Token and stores it as a
195      * public credential in the JAAS subject in a security context.
196      *
197      * Set the identcls field in the security context.
198      *
199      */

200     private void createIdCred(SecurityContext sc, IdentityToken idtok)
201         throws Exception JavaDoc {
202
203         byte[] derenc ; // used to hold DER encodings
204
Any any; // Any object returned from codec.decode_value()
205

206         switch (idtok.discriminator()) {
207
208         case ITTAbsent.value:
209             if(_logger.isLoggable(Level.FINE)){
210                 _logger.log(Level.FINE,"Identity token type is Absent");
211             }
212             sc.identcls = null;
213             break;
214
215         case ITTAnonymous.value:
216             if(_logger.isLoggable(Level.FINE)){
217                 _logger.log(Level.FINE,"Identity token type is Anonymous");
218         _logger.log(Level.FINE,"Adding AnonyCredential to subject's PublicCredentials");
219             }
220             sc.subject.getPublicCredentials().add(new AnonCredential());
221             sc.identcls = AnonCredential.class;
222             break;
223
224         case ITTDistinguishedName.value:
225             /* Construct a X500Name */
226
227             derenc = idtok.dn();
228             /* Issue 5766: Decode CDR encoding if necessary */
229             if (isCDR(derenc)) {
230                 any = codec.decode_value(derenc, X501DistinguishedNameHelper.type());
231
232                 /* Extract CDR encoding */
233                 derenc = X501DistinguishedNameHelper.extract(any);
234             }
235             if(_logger.isLoggable(Level.FINE)){
236                 _logger.log(Level.FINE,"Create an X500Name object from identity token");
237             }
238             X500Name name = new X500Name(derenc);
239         if(_logger.isLoggable(Level.FINE)) {
240                 _logger.log(Level.FINE,"Identity to be asserted is " + name.toString());
241         _logger.log(Level.FINE,"Adding X500Name to subject's PublicCredentials");
242         }
243             sc.subject.getPublicCredentials().add(name);
244             sc.identcls = X500Name.class;
245             break;
246             
247         case ITTX509CertChain.value:
248             /* Construct a X509CertificateChain */
249             if(_logger.isLoggable(Level.FINE)){
250                 _logger.log(Level.FINE,"Identity token type is a X509 Certificate Chain");
251             }
252             derenc = idtok.certificate_chain();
253             /* Issue 5766: Decode CDR encoding if necessary */
254             if (isCDR(derenc)) {
255                 /* Decode CDR encoding */
256                 any = codec.decode_value(derenc, X509CertificateChainHelper.type());
257
258                 /* Extract DER encoding */
259                 derenc = X509CertificateChainHelper.extract(any);
260             }
261
262             DerInputStream din = new DerInputStream(derenc);
263
264             /**
265              * Size specified for getSequence() is 1 and is just
266              * used as a guess by the method getSequence().
267              */

268             DerValue[] derval = din.getSequence(1);
269             X509Certificate JavaDoc[] certchain =
270                         new X509CertImpl[derval.length];
271             /**
272              * X509Certificate does not have a constructor which can
273              * be used to instantiate objects from DER encodings. So
274              * use X509CertImpl extends X509Cerificate and also implements
275              * DerEncoder interface.
276              */

277             if(_logger.isLoggable(Level.FINE)){
278         _logger.log(Level.FINE,"Contents of X509 Certificate chain:");
279             }
280             for (int i = 0; i < certchain.length; i++) {
281                 certchain[i] = new X509CertImpl(derval[i]);
282                 if(_logger.isLoggable(Level.FINE)){
283                 _logger.log(Level.FINE," " + certchain[i].getSubjectDN().getName());
284                 }
285             }
286             if(_logger.isLoggable(Level.FINE)){
287                 _logger.log(Level.FINE,"Creating a X509CertificateCredential object from certchain");
288             }
289             /**
290              * The alias field in the X509CertificateCredential is currently ignored
291              * by the RI. So it is set to "dummy".
292              *
293              */

294             X509CertificateCredential cred =
295                 new X509CertificateCredential(certchain, certchain[0].getSubjectDN().getName(), "default");
296             if(_logger.isLoggable(Level.FINE)){
297                 _logger.log(Level.FINE,"Adding X509CertificateCredential to subject's PublicCredentials");
298             }
299             sc.subject.getPublicCredentials().add(cred);
300             sc.identcls = X509CertificateCredential.class;
301             break;
302  
303         case ITTPrincipalName.value:
304             if(_logger.isLoggable(Level.FINE)){
305         _logger.log(Level.FINE,"Identity token type is GSS Exported Name");
306             }
307             byte[] expname = idtok.principal_name();
308             /* Issue 5766: Decode CDR encoding if necessary */
309             if (isCDR(expname)) {
310                 /* Decode CDR encoding */
311                 any = codec.decode_value(expname, GSS_NT_ExportedNameHelper.type());
312
313                 expname = GSS_NT_ExportedNameHelper.extract(any);
314             }
315             if ( ! GSSUtils.verifyMechOID(GSSUtils.GSSUP_MECH_OID, expname)) {
316                 throw new SecurityException JavaDoc(
317                 localStrings.getLocalString("secserverreqinterceptor.err_unknown_idassert_type",
318                                             "Unknown identity assertion type."));
319             }
320
321             GSSUPName gssname = new GSSUPName(expname);
322
323             sc.subject.getPublicCredentials().add(gssname);
324             sc.identcls = GSSUPName.class;
325             _logger.log(Level.FINE,"Adding GSSUPName credential to subject");
326             break;
327
328         default:
329         _logger.log(Level.SEVERE,"iiop.unknown_identity");
330             throw new SecurityException JavaDoc(
331                 localStrings.getLocalString("secserverreqinterceptor.err_unknown_idassert_type",
332                                             "Unknown identity assertion type."));
333         }
334     }
335
336     /**
337      * Check if given byte is CDR encapsulated.
338      * @param bytes an input array of byte
339      * @return boolean indicates whether input is CDR
340      */

341     private boolean isCDR(byte[] bytes) {
342         return (bytes != null && bytes.length > 0 &&
343                 (bytes[0] == 0x0 || bytes[0] == 0x1));
344     }
345
346     /**
347      * Create an auth credential from authentication token and store
348      * it as a private credential in the JAAS subject in the security
349      * context.
350      *
351      * Set the authcls field in the security context.
352      *
353      * This method currently only works for PasswordCredential tokens.
354      */

355     private void createAuthCred(SecurityContext sc, byte[] authtok) throws Exception JavaDoc
356     {
357         _logger.log(Level.FINE,"Constructing a PasswordCredential from client authentication token");
358         /* create a GSSUPToken from the authentication token */
359         GSSUPToken tok = GSSUPToken.getServerSideInstance(orb, codec, authtok);
360
361         final PasswordCredential pwdcred = tok.getPwdcred();
362         final SecurityContext fsc = sc;
363         if(_logger.isLoggable(Level.FINE)) {
364         _logger.log(Level.FINE,"Password credential = " + pwdcred.toString());
365         _logger.log(Level.FINE,"Adding PasswordCredential to subject's PrivateCredentials");
366     }
367         java.security.AccessController.doPrivileged(new java.security.PrivilegedAction JavaDoc() {
368             public java.lang.Object JavaDoc run() {
369                 fsc.subject.getPrivateCredentials().add(pwdcred);
370                 return null;
371             }
372         });
373         sc = fsc;
374         sc.authcls = PasswordCredential.class;
375     }
376     
377     public void receive_request(ServerRequestInfo ri)
378          throws ForwardRequest
379     {
380         SecurityContext seccontext = null; // SecurityContext to be sent
381
ServiceContext sc = null; // service context
382
int status = 0;
383         boolean raise_no_perm = false;
384
385         if (_logger.isLoggable(Level.FINE)) {
386             _logger.log(Level.FINE, "++++ Entered " + prname + "receive_request");
387         }
388         
389         secsvc = Csiv2Manager.getSecurityService();
390         orb = ORBManager.getORB();
391
392         /**
393          * An unprotected invocation will not contain anything in the serivce
394          * context field for the security context. This will therefore generate
395          * the exception org.omg.CORBA.BAD_PARAM with a minor error code
396          *
397          * com.sun.corba.ee.internal.Interceptors.MinorCodes.INVALID_SERVICE_CONTEXT_ID
398          *
399          * ISSUE: The minor code should probably be checked.
400          */

401
402         try {
403             sc = ri.get_request_service_context(SECURITY_ATTRIBUTE_SERVICE_ID);
404         } catch (org.omg.CORBA.BAD_PARAM JavaDoc e) {
405         if(_logger.isLoggable(Level.FINE)){
406         _logger.log(Level.FINE,"No SAS context element found in service context list");
407         }
408         int secStatus = secsvc.setSecurityContext(null, ri.object_id(),
409                             ri.operation());
410             
411             if (secStatus == SecurityService.STATUS_FAILED){
412                 SASContextBody sasctxbody = createContextError(INVALID_MECHANISM_MAJOR,
413                                                                INVALID_MECHANISM_MINOR);
414                 sc = createSvcContext(sasctxbody);
415                 ri.add_reply_service_context(sc, NO_REPLACE);
416         if(_logger.isLoggable(Level.FINE)) {
417             _logger.log(Level.FINE,
418                 "SecServerRequestInterceptor.receive_request: NO_PERMISSION");
419         }
420                 throw new NO_PERMISSION();
421             }
422             return;
423         }
424
425         if(_logger.isLoggable(Level.FINE)){
426         _logger.log(Level.FINE,"Received a non null SAS context element");
427         }
428         /* Decode the service context field */
429         Any SasAny = orb.create_any();
430         try {
431             SasAny = codec.decode_value(sc.context_data, SASContextBodyHelper.type());
432         } catch (Exception JavaDoc e) {
433         _logger.log(Level.SEVERE,"iiop.decode_exception",e);
434             throw new SecurityException JavaDoc(
435                 localStrings.getLocalString("secserverreqinterceptor.err_cdr_decode",
436                                             "CDR Decoding error for SAS context element."));
437         }
438
439         if(_logger.isLoggable(Level.FINE)){
440         _logger.log(Level.FINE,"Successfully decoded CDR encoded SAS context element.");
441         }
442         SASContextBody sasctxbody = SASContextBodyHelper.extract(SasAny);
443
444         short sasdiscr = sasctxbody.discriminator();
445         if(_logger.isLoggable(Level.FINE)){
446         _logger.log(Level.FINE,"SAS context element is a/an " + SvcContextUtils.getMsgname(sasdiscr)+ " message");
447         }
448         /* Check message type received */
449
450         /**
451          * CSIV2 SPEC NOTE:
452          *
453          * Section 4.3 "TSS State Machine" , table 4-4 "TSS State Table"
454          * shows that a MessageInContext can be received. In this case
455          * the table is somewhat unclear. But in this case a ContextError
456          * with the status code "No Context" ( specified in
457          * section 4.5 "ContextError Values and Exceptions" must be sent back.
458          * A NO_PERMISSION exception must also be raised.
459          *
460          * ISSUE: should setSecurityContext(null) be called ?
461          */

462
463         if (sasdiscr == MTMessageInContext.value) {
464              sasctxbody = createContextError(SvcContextUtils.MessageInContextMinor);
465              sc = createSvcContext(sasctxbody);
466         if(_logger.isLoggable(Level.FINE)){
467         _logger.log(Level.FINE,"Adding ContextError message to service context list");
468         _logger.log(Level.FINE,"SecurityContext set to null");
469         }
470              ri.add_reply_service_context(sc, NO_REPLACE);
471              // no need to set the security context
472
// secsvc.setSecurityContext(null, ri.object_id(), ri.operation());
473

474              throw new NO_PERMISSION();
475         }
476
477         /**
478          * CSIV2 SPEC NOTE:
479          *
480          * CSIV2 spec does not specify the actions for any message other than
481          * a MessageInContext and EstablishContext message.So for such messages,
482          * this implementation simply drops the message on the floor. No
483          * other message is sent back. Neither is an exception raised.
484          *
485          * ISSUE: Should there be some other action ?
486          */

487
488         if (sasdiscr != MTEstablishContext.value) {
489             _logger.log(Level.SEVERE,"iiop.not_establishcontext_msg");
490             throw new SecurityException JavaDoc(
491                 localStrings.getLocalString("secserverreqinterceptor.err_not_ec_msg",
492                                             "Received message not an EstablishContext message."));
493         }
494  
495         EstablishContext ec = sasctxbody.establish_msg();
496
497         seccontext = new SecurityContext();
498         seccontext.subject = new Subject();
499         
500         try {
501             if (ec.client_authentication_token.length != 0) {
502                 if(_logger.isLoggable(Level.FINE)){
503                     _logger.log(Level.FINE,"Message contains Client Authentication Token");
504                 }
505                 createAuthCred(seccontext, ec.client_authentication_token);
506             }
507         } catch (Exception JavaDoc e) {
508             _logger.log(Level.SEVERE,"iiop.authentication_exception",e);
509             throw new SecurityException JavaDoc(
510                 localStrings.getLocalString("secsercverreqinterceptor.err_cred_create",
511                                             "Error while creating a JAAS subject credential."));
512
513
514         }
515
516         try{
517             if (ec.identity_token != null) {
518                 if(_logger.isLoggable(Level.FINE)){
519                     _logger.log(Level.FINE,"Message contains an Identity Token");
520                 }
521                 createIdCred(seccontext, ec.identity_token);
522             }
523         } catch (SecurityException JavaDoc secex){
524             _logger.log(Level.SEVERE,"iiop.security_exception",secex);
525             sasctxbody = createContextError(INVALID_MECHANISM_MAJOR,
526                                             INVALID_MECHANISM_MINOR);
527             sc = createSvcContext(sasctxbody);
528             ri.add_reply_service_context(sc, NO_REPLACE);
529             throw new NO_PERMISSION();
530         } catch (Exception JavaDoc e) {
531             _logger.log(Level.SEVERE,"iiop.generic_exception",e);
532             throw new SecurityException JavaDoc(
533                                         localStrings.getLocalString("secsercverreqinterceptor.err_cred_create",
534                                                                     "Error while creating a JAAS subject credential."));
535             
536         }
537
538         if(_logger.isLoggable(Level.FINE)){
539             _logger.log(Level.FINE,"Invoking setSecurityContext() to set security context");
540         }
541         status = secsvc.setSecurityContext(seccontext, ri.object_id(), ri.operation());
542     if(_logger.isLoggable(Level.FINE)){
543         _logger.log(Level.FINE,"setSecurityContext() returned status code " + status);
544         }
545         /**
546          * CSIV2 SPEC NOTE:
547          *
548          * If ec.client_context_id is non zero, then this is a stateful
549          * request. As specified in section 4.2.1, a stateless server must
550          * attempt to validate the security tokens in the security context
551          * field. If validation succeeds then CompleteEstablishContext message
552          * is sent back. If validation fails, a ContextError must be sent back.
553          */

554         if (status == SecurityService.STATUS_FAILED) {
555             if(_logger.isLoggable(Level.FINE)){
556         _logger.log(Level.FINE,"setSecurityContext() returned STATUS_FAILED");
557             }
558             sasctxbody = createContextError(status);
559             sc = createSvcContext(sasctxbody);
560             if(_logger.isLoggable(Level.FINE)){
561         _logger.log(Level.FINE,"Adding ContextError message to service context list");
562             }
563             ri.add_reply_service_context(sc, NO_REPLACE);
564             throw new NO_PERMISSION();
565         }
566
567         if(_logger.isLoggable(Level.FINE)){
568         _logger.log(Level.FINE,"setSecurityContext() returned SUCCESS");
569         }
570         sasctxbody = createCompleteEstablishContext(status);
571         sc = createSvcContext(sasctxbody);
572         if(_logger.isLoggable(Level.FINE)){
573             _logger.log(Level.FINE,"Adding CompleteEstablisContext message to service context list");
574         }
575         ri.add_reply_service_context(sc, NO_REPLACE);
576     }
577
578     /* This method is keeping a track of when to unset the security context
579      * Currently with the re-use of the threads made by the orb the security
580      * context does not get unset. This method determines when to unset the
581      * security context
582      */

583     public void receive_request_service_contexts(ServerRequestInfo ri)
584          throws ForwardRequest
585     {
586         // cannot set this in receive_request due to the PI flow control
587
// semantics. e.g. if receive_req for some other PI throws an
588
// exception - the send_exception will be called that will muck
589
// the stack up
590
Counter cntr = (Counter)counterForCalls.get();
591         if (cntr == null){
592             cntr = new Counter();
593             counterForCalls.set(cntr);
594         }
595         if (cntr.count == 0){
596             SecurityService secsvc = Csiv2Manager.getSecurityService();
597             secsvc.unsetSecurityContext();
598         }
599         cntr.increment();
600     }
601
602     public void send_reply(ServerRequestInfo ri)
603     {
604         unsetSecurityContext();
605     }
606  
607     public void send_exception(ServerRequestInfo ri)
608          throws ForwardRequest
609     {
610         unsetSecurityContext();
611     }
612    
613     public void send_other(ServerRequestInfo ri)
614          throws ForwardRequest
615     {
616         unsetSecurityContext();
617     }
618
619     public void destroy()
620     {
621     }
622
623     private void unsetSecurityContext(){
624         Counter cntr = (Counter)counterForCalls.get();
625         if (cntr == null){ // sanity check
626
cntr = new Counter(1);
627         }
628         cntr.decrement();
629         if (cntr.count == 0){
630             SecurityService secsvc = Csiv2Manager.getSecurityService();
631             secsvc.unsetSecurityContext();
632         }
633     }
634 }
635
636 class Counter {
637     
638     public int count = 0;
639     public Counter(int count){
640         this.count = count;
641     }
642     public Counter(){
643         count = 0;
644     }
645     public void setCount(int counter){
646         count = counter;
647     }
648     public void increment(){
649         count++;
650     }
651     public void decrement(){
652         count--;
653     }
654     public String JavaDoc display(){
655          return " Counter = " +count;
656     }
657 }
658
Popular Tags