001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Marc Wick.
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.controller.jmx;
022:
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Set;
028:
029: import javax.management.InstanceNotFoundException;
030: import javax.management.MBeanException;
031: import javax.management.MBeanServer;
032: import javax.management.ObjectName;
033: import javax.management.ReflectionException;
034: import javax.security.auth.Subject;
035:
036: import org.continuent.sequoia.common.jmx.JmxConstants;
037: import org.continuent.sequoia.common.log.Trace;
038: import org.continuent.sequoia.common.users.AbstractDatabaseUser;
039:
040: /**
041: * An MBeanServer authenticating all invoke() requests.
042: *
043: * @author <a href="mailto:marc.wick@monte-bre.ch">Marc Wick </a>
044: * @author <a href="mailto:nicolas.modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
045: * @version 1.0
046: */
047: public class AuthenticatingMBeanServer extends ChainedMBeanServer {
048:
049: /** Logger instance */
050: static Trace logger = Trace
051: .getLogger("org.continuent.sequoia.controller.jmx.AuthenticatingMBeanServer");
052:
053: /**
054: * Overridden just to make it public
055: * <p>
056: *
057: * @see org.continuent.sequoia.controller.jmx.ChainedMBeanServer#setMBeanServer(javax.management.MBeanServer)
058: */
059: public void setMBeanServer(MBeanServer server) {
060: super .setMBeanServer(server);
061: }
062:
063: /**
064: * @see javax.management.MBeanServerConnection#invoke(javax.management.ObjectName,
065: * java.lang.String, java.lang.Object[], java.lang.String[])
066: */
067: public Object invoke(ObjectName name, String operationName,
068: Object[] params, String[] signature)
069: throws InstanceNotFoundException, MBeanException,
070: ReflectionException {
071: if (JmxConstants.mbeanNeedAuthentication(name)
072: && (operationName
073: .equalsIgnoreCase("checkAdminAuthentication") == false)) {
074: // we have to check all methods that access a virtual database
075: // except
076: // authentication
077: boolean authenticationOk = false;
078: String username = null;
079: String password = null;
080:
081: Subject subject = Subject
082: .getSubject(java.security.AccessController
083: .getContext());
084: if (subject == null || subject.getPrincipals().size() == 0) {
085: username = (String) params[0];
086: password = (String) params[1];
087: authenticationOk = authenticate(name, username,
088: password);
089: if (!authenticationOk)
090: throw new MBeanException(
091: new Exception(
092: "Authentication failed (username,password) invalid"));
093:
094: if (logger.isDebugEnabled())
095: logger
096: .debug("Authentication with username and password was successfull");
097:
098: // we have to strip the username and password from the params
099: // and args
100: return super .invoke(name, operationName,
101: cleanO(params), cleanS(signature));
102: } else {
103: Set principals = subject
104: .getPrincipals(AbstractDatabaseUser.class);
105: for (Iterator it = principals.iterator(); it.hasNext();) {
106: AbstractDatabaseUser user = (AbstractDatabaseUser) it
107: .next();
108: username = user.getName();
109: password = user.getPassword();
110: authenticationOk = authenticate(name, username,
111: password);
112: if (authenticationOk)
113: break;
114: }
115:
116: if (principals.size() == 0 && logger.isDebugEnabled())
117: throw new MBeanException(new Exception(
118: "Authentication failed : no principal"));
119:
120: if (!authenticationOk)
121: throw new MBeanException(
122: new Exception(
123: "Authentication failed : principal invalid"));
124: if (logger.isDebugEnabled())
125: logger
126: .debug("Authentication with principal was successfull");
127: return super .invoke(name, operationName, params,
128: signature);
129: }
130: } else {
131: if (logger.isDebugEnabled())
132: logger.debug("no authentication required");
133:
134: return super .invoke(name, operationName, params, signature);
135: }
136: }
137:
138: private boolean authenticate(ObjectName name, String username,
139: String password) {
140: try {
141: String type = name.getKeyProperty("type");
142: boolean vdb = JmxConstants.VIRTUALDATABASE_TYPE_VALUE
143: .equals(type);
144: if (vdb)
145: return ((Boolean) invoke(name,
146: "checkAdminAuthentication", new Object[] {
147: username, password },
148: new String[] { "java.lang.String",
149: "java.lang.String" })).booleanValue();
150: else {
151: boolean backend = JmxConstants.DATABASEBACKEND_TYPE_VALUE
152: .equals(type);
153: if (backend) {
154: String virtualDataBaseName = name
155: .getKeyProperty(JmxConstants.VIRTUALDATABASE_PROPERTY);
156: if (virtualDataBaseName == null) {
157: return false;
158: }
159: // Check with the owning database if the password is right
160: ObjectName vdbName = JmxConstants
161: .getVirtualDataBaseObjectName(virtualDataBaseName);
162: return ((Boolean) invoke(vdbName,
163: "checkAdminAuthentication", new Object[] {
164: username, password }, new String[] {
165: "java.lang.String",
166: "java.lang.String" }))
167: .booleanValue();
168: } else
169: // No further check ...
170: return true;
171: }
172: } catch (Exception e) {
173: if (logger.isDebugEnabled()) {
174: logger
175: .debug("authentication failed with exception ",
176: e);
177: }
178: return false;
179: }
180: }
181:
182: private static Object[] cleanO(Object[] params) {
183: List o = Arrays.asList(params);
184: o = o.subList(2, o.size());
185: return (new ArrayList(o).toArray());
186: }
187:
188: private static String[] cleanS(String[] params) {
189: List o = Arrays.asList(params);
190: o = o.subList(2, o.size());
191: String[] s = new String[o.size()];
192: return (String[]) new ArrayList(o).toArray(s);
193: }
194: }
|