001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ServerInterceptor.java 9905 2007-01-05 12:34:30Z benoitf $
023: * --------------------------------------------------------------------------
024: *
025: */package org.objectweb.jonas.security.interceptors.jrmp.ctxcheck;
026:
027: import java.io.IOException;
028: import java.security.InvalidKeyException;
029: import java.security.NoSuchAlgorithmException;
030: import java.security.PublicKey;
031: import java.security.Signature;
032: import java.security.SignatureException;
033: import java.util.Arrays;
034:
035: import org.objectweb.carol.rmi.jrmp.interceptor.JServerRequestInfo;
036: import org.objectweb.carol.rmi.jrmp.interceptor.JServerRequestInterceptor;
037: import org.objectweb.security.context.SecurityContext;
038: import org.objectweb.security.context.SecurityCurrent;
039:
040: /**
041: * Checks that the security context that has been unserialized on the server
042: * side has a valid signature (Nobody has changed its value).
043: * @author Florent Benoit
044: */
045: public class ServerInterceptor implements JServerRequestInterceptor {
046:
047: /**
048: * JProp fully qualified Classname
049: */
050: private static final String JPROP_CLASSNAME = "org.objectweb.jonas.common.JProp";
051:
052: /**
053: * Anonymous security context.
054: */
055: private static final SecurityContext ANON_CTX = new SecurityContext();
056:
057: /**
058: * Security context with an altered identity : like Anonymous.
059: */
060: private static SecurityContext alteredCtx = null;
061:
062: /**
063: * Interceptor name.
064: */
065: private static final String NAME = "CHECK_CTX_INTERCEPTOR";
066:
067: /**
068: * Configuration used to check the signature.
069: */
070: private static CtxCheckConfig config = null;
071:
072: /**
073: * Default constructor.
074: */
075: public ServerInterceptor() {
076: // If server side
077: if (config == null) {
078: boolean hasJonasBase = System.getProperty("jonas.base") != null;
079: boolean hasJonasRoot = System.getProperty("install.root") != null;
080: boolean server = true;
081: try {
082: Thread.currentThread().getContextClassLoader()
083: .loadClass(JPROP_CLASSNAME);
084: } catch (ClassNotFoundException cnfe) {
085: server = false;
086: }
087: if (server && hasJonasBase && hasJonasRoot) {
088: config = new CtxCheckConfig();
089: }
090: }
091:
092: if (alteredCtx == null) {
093: alteredCtx = new SecurityContext("JOnAS_ALTERED_IDENTITY");
094: }
095: }
096:
097: /**
098: * Receive request
099: * @param JServerRequestInfo the jrmp server request information
100: * @exception IOException if an exception occurs with the ObjectOutput
101: */
102: public void receive_request(JServerRequestInfo jri)
103: throws IOException {
104: // Gets SecurityCurrent object (always existing in JOnAS Server)
105: SecurityCurrent current = SecurityCurrent.getCurrent();
106: if (current != null) {
107: // Get Security context
108: SecurityContext sctx = current.getSecurityContext();
109:
110: // There is a context ?
111: if (sctx != null) {
112: // Anonymous context ?
113: if (ANON_CTX.getPrincipalName().equals(
114: sctx.getPrincipalName())
115: && Arrays.equals(ANON_CTX.getRoles(), sctx
116: .getRoles())) {
117: return;
118: }
119:
120: // Not the anonymous context, needs to validate
121:
122: // No signature = error ! change the security context and raise an error
123: if (sctx.getSignature() == null) {
124: current.setSecurityContext(alteredCtx);
125: throw new IOException(
126: "The security context '"
127: + sctx
128: + "' has no signature which is illegal with this configuration. Check that the SignLoginModule has been used.");
129: }
130:
131: // Get public key
132: PublicKey publickey = config.getPublicKey();
133:
134: // Build signature with data to validate (principal name + roles)
135: Signature signature = null;
136: try {
137: signature = Signature.getInstance("SHA1withDSA");
138: } catch (NoSuchAlgorithmException e) {
139: current.setSecurityContext(alteredCtx);
140: throw new IOException(
141: "Error while getting the algorithm 'SHA1withDSA' :"
142: + e.getMessage());
143: }
144:
145: try {
146: signature.initVerify(publickey);
147: } catch (InvalidKeyException e) {
148: current.setSecurityContext(alteredCtx);
149: throw new IOException(
150: "Cannot initialize the signature with the given public key:"
151: + e.getMessage());
152: }
153:
154: // Add principal name
155: try {
156: signature
157: .update(sctx.getPrincipalName().getBytes());
158: } catch (SignatureException e) {
159: current.setSecurityContext(alteredCtx);
160: throw new IOException(
161: "Cannot add the bytes for the principal name '"
162: + sctx.getPrincipalName() + "' :"
163: + e.getMessage());
164: }
165:
166: // Add roles
167: String[] roles = sctx.getRoles();
168: for (int r = 0; r < roles.length; r++) {
169: try {
170: signature.update(roles[r].getBytes());
171: } catch (SignatureException e) {
172: current.setSecurityContext(alteredCtx);
173: throw new IOException(
174: "Cannot add the bytes for the role '"
175: + roles[r] + "' :"
176: + e.getMessage());
177: }
178: }
179:
180: // Check signature
181: boolean trusted = false;
182: try {
183: trusted = signature.verify(sctx.getSignature());
184: } catch (SignatureException e) {
185: current.setSecurityContext(alteredCtx);
186: throw new IOException(
187: "The signature found in the security context '"
188: + sctx + "' is invalid:"
189: + e.getMessage());
190: }
191:
192: // Invalid signature !
193: if (!trusted) {
194: current.setSecurityContext(alteredCtx);
195: throw new IOException(
196: "The signature for the security context '"
197: + sctx
198: + "' has been altered by an unknown source.");
199: }
200:
201: }
202:
203: }
204: }
205:
206: /**
207: * send reply with context
208: * @param JServerRequestInfo the jrmp server request information
209: * @exception IOException if an exception occur with the ObjectOutput
210: */
211: public void send_reply(JServerRequestInfo jri) throws IOException {
212: // Do nothing
213: }
214:
215: /**
216: * get the name of this interceptor
217: * @return name
218: */
219: public String name() {
220: return NAME;
221: }
222:
223: public void send_exception(JServerRequestInfo jri)
224: throws IOException {
225: }
226:
227: public void send_other(JServerRequestInfo jri) throws IOException {
228: }
229: }
|