001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.iiop.csiv2;
023:
024: /***************************************
025: * *
026: * JBoss: The OpenSource J2EE WebOS *
027: * *
028: * Distributable under LGPL license. *
029: * See terms of license at gnu.org. *
030: * *
031: ***************************************/
032:
033: import java.security.Principal;
034:
035: import org.omg.CORBA.Any;
036: import org.omg.CORBA.BAD_PARAM;
037: import org.omg.CORBA.MARSHAL;
038: import org.omg.CORBA.NO_PERMISSION;
039: import org.omg.CORBA.ORB;
040: import org.omg.CORBA.CompletionStatus;
041: import org.omg.CORBA.LocalObject;
042: import org.omg.CORBA.TCKind;
043: import org.omg.CSI.AuthorizationElement;
044: import org.omg.CSI.EstablishContext;
045: import org.omg.CSI.IdentityToken;
046: import org.omg.CSI.MTContextError;
047: import org.omg.CSI.SASContextBody;
048: import org.omg.CSI.SASContextBodyHelper;
049:
050: import org.omg.CSIIOP.CompoundSecMech;
051: import org.omg.CSIIOP.TAG_CSI_SEC_MECH_LIST;
052: import org.omg.CSIIOP.CompoundSecMechListHelper;
053: import org.omg.CSIIOP.CompoundSecMechList;
054: import org.omg.CSIIOP.AS_ContextSec;
055: import org.omg.CSIIOP.SAS_ContextSec;
056: import org.omg.CSIIOP.EstablishTrustInClient;
057:
058: import org.omg.GSSUP.InitialContextToken;
059: import org.omg.IOP.Codec;
060: import org.omg.IOP.CodecPackage.FormatMismatch;
061: import org.omg.IOP.CodecPackage.TypeMismatch;
062: import org.omg.IOP.ServiceContext;
063: import org.omg.IOP.TaggedComponent;
064: import org.omg.PortableInterceptor.ClientRequestInfo;
065: import org.omg.PortableInterceptor.ClientRequestInterceptor;
066: import org.jacorb.orb.MinorCodes;
067:
068: import org.jboss.logging.Logger;
069: import org.jboss.security.SecurityAssociation;
070:
071: /**
072: * This implementation of
073: * <code>org.omg.PortableInterceptor.ClientRequestInterceptor</code> inserts
074: * the security attribute service (SAS) context into outgoing IIOP requests
075: * and handles the SAS messages received from the target security service
076: * in the SAS context of incoming IIOP replies.
077: *
078: * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
079: * @version $Revision: 57194 $
080: */
081: public class SASClientInterceptor extends LocalObject implements
082: ClientRequestInterceptor {
083: // Constants ------------------------------------------------------
084: /** @since 4.0.2 */
085: private static final long serialVersionUID = 5744355993699264087L;
086:
087: private static final int sasContextId = org.omg.IOP.SecurityAttributeService.value;
088:
089: private static final IdentityToken absentIdentityToken;
090: static {
091: absentIdentityToken = new IdentityToken();
092: absentIdentityToken.absent(true);
093: }
094: private static final AuthorizationElement[] noAuthorizationToken = {};
095:
096: private static final Logger log = Logger
097: .getLogger(SASTargetInterceptor.class);
098: private static final boolean traceEnabled = log.isTraceEnabled();
099:
100: // Fields ---------------------------------------------------------
101:
102: private Codec codec;
103:
104: // Constructor ---------------------------------------------------
105:
106: public SASClientInterceptor(Codec codec) {
107: this .codec = codec;
108: }
109:
110: // Methods -------------------------------------------------------
111:
112: // org.omg.PortableInterceptor.Interceptor operations ------------
113:
114: public String name() {
115: return "SASClientInterceptor";
116: }
117:
118: public void destroy() {
119: // do nothing
120: }
121:
122: // ClientRequestInterceptor operations ---------------------------
123:
124: public void send_request(ClientRequestInfo ri) {
125: try {
126: CompoundSecMech secMech = CSIv2Util
127: .getMatchingSecurityMech(ri, codec,
128: EstablishTrustInClient.value, /* client supports */
129: (short) 0 /* client requires */);
130: if (secMech == null)
131: return;
132:
133: if ((secMech.as_context_mech.target_supports & EstablishTrustInClient.value) != 0) {
134: Principal p = SecurityAssociation.getPrincipal();
135: if (p != null) {
136: byte[] encodedTargetName = secMech.as_context_mech.target_name;
137:
138: // The name scope needs to be externalized
139: String name = p.getName();
140: if (name.indexOf('@') < 0) {
141: byte[] decodedTargetName = CSIv2Util
142: .decodeGssExportedName(encodedTargetName);
143: String targetName = new String(
144: decodedTargetName, "UTF-8");
145: name += "@" + targetName; // "@default"
146: }
147: byte[] username = name.getBytes("UTF-8");
148: // I don't know why there is not a better way
149: // to go from char[] -> byte[]
150: Object credential = SecurityAssociation
151: .getCredential();
152: byte[] password = {};
153: if (credential instanceof char[]) {
154: String tmp = new String((char[]) credential);
155: password = tmp.getBytes("UTF-8");
156: } else if (credential instanceof byte[])
157: password = (byte[]) credential;
158: else if (credential != null) {
159: String tmp = credential.toString();
160: password = tmp.getBytes("UTF-8");
161: }
162:
163: // create authentication token
164: InitialContextToken authenticationToken = new InitialContextToken(
165: username, password, encodedTargetName);
166: // ASN.1-encode it, as defined in RFC 2743
167: byte[] encodedAuthenticationToken = CSIv2Util
168: .encodeInitialContextToken(
169: authenticationToken, codec);
170:
171: // create EstablishContext message with the encoded token
172: EstablishContext message = new EstablishContext(
173: 0, // stateless ctx id
174: noAuthorizationToken, absentIdentityToken,
175: encodedAuthenticationToken);
176:
177: // create SAS context with the EstablishContext message
178: SASContextBody contextBody = new SASContextBody();
179: contextBody.establish_msg(message);
180:
181: // stuff the SAS context into the outgoing request
182: Any any = ORB.init().create_any();
183: SASContextBodyHelper.insert(any, contextBody);
184: ServiceContext sc = new ServiceContext(
185: sasContextId, codec.encode_value(any));
186: ri
187: .add_request_service_context(sc, true /*replace existing context*/);
188: }
189: }
190: } catch (java.io.UnsupportedEncodingException e) {
191: throw new MARSHAL("Unexpected exception: " + e);
192: } catch (org.omg.IOP.CodecPackage.InvalidTypeForEncoding e) {
193: throw new MARSHAL("Unexpected exception: " + e);
194: }
195: }
196:
197: public void send_poll(ClientRequestInfo ri) {
198: // do nothing
199: }
200:
201: public void receive_reply(ClientRequestInfo ri) {
202: try {
203: ServiceContext sc = ri
204: .get_reply_service_context(sasContextId);
205: Any msg = codec.decode_value(sc.context_data,
206: SASContextBodyHelper.type());
207: SASContextBody contextBody = SASContextBodyHelper
208: .extract(msg);
209:
210: // At this point contextBody should contain a
211: // CompleteEstablishContext message, which does not require any
212: // treatment. ContextError messages should arrive via
213: // receive_exception().
214:
215: if (traceEnabled)
216: log.trace("receive_reply: got SAS reply, type "
217: + contextBody.discriminator());
218:
219: if (contextBody.discriminator() == MTContextError.value) {
220: // should not happen
221: log.warn("Unexpected ContextError in SAS reply");
222: throw new NO_PERMISSION(
223: "Unexpected ContextError in SAS reply",
224: MinorCodes.SAS_CSS_FAILURE,
225: CompletionStatus.COMPLETED_YES);
226: }
227: } catch (BAD_PARAM e) {
228: // no service context with sasContextId: do nothing
229: } catch (FormatMismatch e) {
230: throw new MARSHAL("Could not parse SAS reply: " + e, 0,
231: CompletionStatus.COMPLETED_YES);
232: } catch (TypeMismatch e) {
233: throw new MARSHAL("Could not parse SAS reply: " + e, 0,
234: CompletionStatus.COMPLETED_YES);
235: }
236: }
237:
238: public void receive_exception(ClientRequestInfo ri) {
239: try {
240: ServiceContext sc = ri
241: .get_reply_service_context(sasContextId);
242: Any msg = codec.decode_value(sc.context_data,
243: SASContextBodyHelper.type());
244: SASContextBody contextBody = SASContextBodyHelper
245: .extract(msg);
246:
247: // At this point contextBody may contain a either a
248: // CompleteEstablishContext message or a ContextError message.
249: // Neither message requires any treatment. We decoded the context
250: // body just to check that it contains a well-formed message.
251:
252: if (traceEnabled)
253: log.trace("receive_exception: got SAS reply, type "
254: + contextBody.discriminator());
255: } catch (BAD_PARAM e) {
256: // no service context with sasContextId: do nothing
257: } catch (FormatMismatch e) {
258: throw new MARSHAL("Could not parse SAS reply: " + e,
259: MinorCodes.SAS_CSS_FAILURE,
260: CompletionStatus.COMPLETED_MAYBE);
261: } catch (TypeMismatch e) {
262: throw new MARSHAL("Could not parse SAS reply: " + e,
263: MinorCodes.SAS_CSS_FAILURE,
264: CompletionStatus.COMPLETED_MAYBE);
265: }
266: }
267:
268: public void receive_other(ClientRequestInfo ri) {
269: // do nothing
270: }
271:
272: }
|