1 /*
2 * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jmx.remote.security;
27
28 import java.io.IOException;
29 import java.security.AccessController;
30 import java.security.Principal;
31 import java.security.PrivilegedAction;
32 import java.security.PrivilegedActionException;
33 import java.security.PrivilegedExceptionAction;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.Map;
37 import java.util.Properties;
38 import javax.management.remote.JMXPrincipal;
39 import javax.management.remote.JMXAuthenticator;
40 import javax.security.auth.AuthPermission;
41 import javax.security.auth.Subject;
42 import javax.security.auth.callback.*;
43 import javax.security.auth.login.AppConfigurationEntry;
44 import javax.security.auth.login.Configuration;
45 import javax.security.auth.login.LoginContext;
46 import javax.security.auth.login.LoginException;
47 import javax.security.auth.spi.LoginModule;
48 import com.sun.jmx.remote.util.ClassLogger;
49 import com.sun.jmx.remote.util.EnvHelp;
50
51 /**
52 * <p>This class represents a
53 * <a href="{@docRoot}/../guide/security/jaas/JAASRefGuide.html">JAAS</a>
54 * based implementation of the {@link JMXAuthenticator} interface.</p>
55 *
56 * <p>Authentication is performed by passing the supplied user's credentials
57 * to one or more authentication mechanisms ({@link LoginModule}) for
58 * verification. An authentication mechanism acquires the user's credentials
74 * {@link PasswordCallback} and that they return a {@link Subject} filled-in
75 * with a {@link Principal}, for those users that are successfully
76 * authenticated.</p>
77 */
78 public final class JMXPluggableAuthenticator implements JMXAuthenticator {
79
80 /**
81 * Creates an instance of <code>JMXPluggableAuthenticator</code>
82 * and initializes it with a {@link LoginContext}.
83 *
84 * @param env the environment containing configuration properties for the
85 * authenticator. Can be null, which is equivalent to an empty
86 * Map.
87 * @exception SecurityException if the authentication mechanism cannot be
88 * initialized.
89 */
90 public JMXPluggableAuthenticator(Map<?, ?> env) {
91
92 String loginConfigName = null;
93 String passwordFile = null;
94
95 if (env != null) {
96 loginConfigName = (String) env.get(LOGIN_CONFIG_PROP);
97 passwordFile = (String) env.get(PASSWORD_FILE_PROP);
98 }
99
100 try {
101
102 if (loginConfigName != null) {
103 // use the supplied JAAS login configuration
104 loginContext =
105 new LoginContext(loginConfigName, new JMXCallbackHandler());
106
107 } else {
108 // use the default JAAS login configuration (file-based)
109 SecurityManager sm = System.getSecurityManager();
110 if (sm != null) {
111 sm.checkPermission(
112 new AuthPermission("createLoginContext." +
113 LOGIN_CONFIG_NAME));
114 }
115
116 final String pf = passwordFile;
117 try {
118 loginContext = AccessController.doPrivileged(
119 new PrivilegedExceptionAction<LoginContext>() {
120 public LoginContext run() throws LoginException {
121 return new LoginContext(
122 LOGIN_CONFIG_NAME,
123 null,
124 new JMXCallbackHandler(),
125 new FileLoginConfig(pf));
126 }
127 });
128 } catch (PrivilegedActionException pae) {
129 throw (LoginException) pae.getException();
130 }
131 }
132
133 } catch (LoginException le) {
134 authenticationFailure("authenticate", le);
135
136 } catch (SecurityException se) {
137 authenticationFailure("authenticate", se);
138 }
139 }
140
141 /**
142 * Authenticate the <code>MBeanServerConnection</code> client
143 * with the given client credentials.
144 *
145 * @param credentials the user-defined credentials to be passed in
233
234 private static void logException(String method,
235 String message,
236 Exception e) {
237 if (logger.traceOn()) {
238 logger.trace(method, message);
239 }
240 if (logger.debugOn()) {
241 logger.debug(method, e);
242 }
243 }
244
245 private LoginContext loginContext;
246 private String username;
247 private String password;
248 private static final String LOGIN_CONFIG_PROP =
249 "jmx.remote.x.login.config";
250 private static final String LOGIN_CONFIG_NAME = "JMXPluggableAuthenticator";
251 private static final String PASSWORD_FILE_PROP =
252 "jmx.remote.x.password.file";
253 private static final ClassLogger logger =
254 new ClassLogger("javax.management.remote.misc", LOGIN_CONFIG_NAME);
255
256 /**
257 * This callback handler supplies the username and password (which was
258 * originally supplied by the JMX user) to the JAAS login module performing
259 * the authentication. No interactive user prompting is required because the
260 * credentials are already available to this class (via its enclosing class).
261 */
262 private final class JMXCallbackHandler implements CallbackHandler {
263
264 /**
265 * Sets the username and password in the appropriate Callback object.
266 */
267 public void handle(Callback[] callbacks)
268 throws IOException, UnsupportedCallbackException {
269
270 for (int i = 0; i < callbacks.length; i++) {
271 if (callbacks[i] instanceof NameCallback) {
272 ((NameCallback)callbacks[i]).setName(username);
286 /**
287 * This class defines the JAAS configuration for file-based authentication.
288 * It is equivalent to the following textual configuration entry:
289 * <pre>
290 * JMXPluggableAuthenticator {
291 * com.sun.jmx.remote.security.FileLoginModule required;
292 * };
293 * </pre>
294 */
295 private static class FileLoginConfig extends Configuration {
296
297 // The JAAS configuration for file-based authentication
298 private AppConfigurationEntry[] entries;
299
300 // The classname of the login module for file-based authentication
301 private static final String FILE_LOGIN_MODULE =
302 FileLoginModule.class.getName();
303
304 // The option that identifies the password file to use
305 private static final String PASSWORD_FILE_OPTION = "passwordFile";
306
307 /**
308 * Creates an instance of <code>FileLoginConfig</code>
309 *
310 * @param passwordFile A filepath that identifies the password file to use.
311 * If null then the default password file is used.
312 */
313 public FileLoginConfig(String passwordFile) {
314
315 Map<String, String> options;
316 if (passwordFile != null) {
317 options = new HashMap<String, String>(1);
318 options.put(PASSWORD_FILE_OPTION, passwordFile);
319 } else {
320 options = Collections.emptyMap();
321 }
322
323 entries = new AppConfigurationEntry[] {
324 new AppConfigurationEntry(FILE_LOGIN_MODULE,
325 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
326 options)
327 };
328 }
329
330 /**
331 * Gets the JAAS configuration for file-based authentication
332 */
333 public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
334
335 return name.equals(LOGIN_CONFIG_NAME) ? entries : null;
336 }
337
338 /**
|
1 /*
2 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jmx.remote.security;
27
28 import java.io.IOException;
29 import java.security.AccessController;
30 import java.security.Principal;
31 import java.security.PrivilegedAction;
32 import java.security.PrivilegedActionException;
33 import java.security.PrivilegedExceptionAction;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.Map;
37 import javax.management.remote.JMXAuthenticator;
38 import javax.security.auth.AuthPermission;
39 import javax.security.auth.Subject;
40 import javax.security.auth.callback.*;
41 import javax.security.auth.login.AppConfigurationEntry;
42 import javax.security.auth.login.Configuration;
43 import javax.security.auth.login.LoginContext;
44 import javax.security.auth.login.LoginException;
45 import javax.security.auth.spi.LoginModule;
46 import com.sun.jmx.remote.util.ClassLogger;
47 import com.sun.jmx.remote.util.EnvHelp;
48
49 /**
50 * <p>This class represents a
51 * <a href="{@docRoot}/../guide/security/jaas/JAASRefGuide.html">JAAS</a>
52 * based implementation of the {@link JMXAuthenticator} interface.</p>
53 *
54 * <p>Authentication is performed by passing the supplied user's credentials
55 * to one or more authentication mechanisms ({@link LoginModule}) for
56 * verification. An authentication mechanism acquires the user's credentials
72 * {@link PasswordCallback} and that they return a {@link Subject} filled-in
73 * with a {@link Principal}, for those users that are successfully
74 * authenticated.</p>
75 */
76 public final class JMXPluggableAuthenticator implements JMXAuthenticator {
77
78 /**
79 * Creates an instance of <code>JMXPluggableAuthenticator</code>
80 * and initializes it with a {@link LoginContext}.
81 *
82 * @param env the environment containing configuration properties for the
83 * authenticator. Can be null, which is equivalent to an empty
84 * Map.
85 * @exception SecurityException if the authentication mechanism cannot be
86 * initialized.
87 */
88 public JMXPluggableAuthenticator(Map<?, ?> env) {
89
90 String loginConfigName = null;
91 String passwordFile = null;
92 String hashPasswords = null;
93
94 if (env != null) {
95 loginConfigName = (String) env.get(LOGIN_CONFIG_PROP);
96 passwordFile = (String) env.get(PASSWORD_FILE_PROP);
97 hashPasswords = (String) env.get(HASH_PASSWORDS);
98 }
99
100 try {
101
102 if (loginConfigName != null) {
103 // use the supplied JAAS login configuration
104 loginContext =
105 new LoginContext(loginConfigName, new JMXCallbackHandler());
106
107 } else {
108 // use the default JAAS login configuration (file-based)
109 SecurityManager sm = System.getSecurityManager();
110 if (sm != null) {
111 sm.checkPermission(
112 new AuthPermission("createLoginContext." +
113 LOGIN_CONFIG_NAME));
114 }
115
116 final String pf = passwordFile;
117 final String hashPass = hashPasswords;
118 try {
119 loginContext = AccessController.doPrivileged(
120 new PrivilegedExceptionAction<LoginContext>() {
121 public LoginContext run() throws LoginException {
122 return new LoginContext(
123 LOGIN_CONFIG_NAME,
124 null,
125 new JMXCallbackHandler(),
126 new FileLoginConfig(pf, hashPass));
127 }
128 });
129 } catch (PrivilegedActionException pae) {
130 throw (LoginException) pae.getException();
131 }
132 }
133
134 } catch (LoginException le) {
135 authenticationFailure("authenticate", le);
136
137 } catch (SecurityException se) {
138 authenticationFailure("authenticate", se);
139 }
140 }
141
142 /**
143 * Authenticate the <code>MBeanServerConnection</code> client
144 * with the given client credentials.
145 *
146 * @param credentials the user-defined credentials to be passed in
234
235 private static void logException(String method,
236 String message,
237 Exception e) {
238 if (logger.traceOn()) {
239 logger.trace(method, message);
240 }
241 if (logger.debugOn()) {
242 logger.debug(method, e);
243 }
244 }
245
246 private LoginContext loginContext;
247 private String username;
248 private String password;
249 private static final String LOGIN_CONFIG_PROP =
250 "jmx.remote.x.login.config";
251 private static final String LOGIN_CONFIG_NAME = "JMXPluggableAuthenticator";
252 private static final String PASSWORD_FILE_PROP =
253 "jmx.remote.x.password.file";
254 private static final String HASH_PASSWORDS =
255 "jmx.remote.x.password.hashpasswords";
256 private static final ClassLogger logger =
257 new ClassLogger("javax.management.remote.misc", LOGIN_CONFIG_NAME);
258
259 /**
260 * This callback handler supplies the username and password (which was
261 * originally supplied by the JMX user) to the JAAS login module performing
262 * the authentication. No interactive user prompting is required because the
263 * credentials are already available to this class (via its enclosing class).
264 */
265 private final class JMXCallbackHandler implements CallbackHandler {
266
267 /**
268 * Sets the username and password in the appropriate Callback object.
269 */
270 public void handle(Callback[] callbacks)
271 throws IOException, UnsupportedCallbackException {
272
273 for (int i = 0; i < callbacks.length; i++) {
274 if (callbacks[i] instanceof NameCallback) {
275 ((NameCallback)callbacks[i]).setName(username);
289 /**
290 * This class defines the JAAS configuration for file-based authentication.
291 * It is equivalent to the following textual configuration entry:
292 * <pre>
293 * JMXPluggableAuthenticator {
294 * com.sun.jmx.remote.security.FileLoginModule required;
295 * };
296 * </pre>
297 */
298 private static class FileLoginConfig extends Configuration {
299
300 // The JAAS configuration for file-based authentication
301 private AppConfigurationEntry[] entries;
302
303 // The classname of the login module for file-based authentication
304 private static final String FILE_LOGIN_MODULE =
305 FileLoginModule.class.getName();
306
307 // The option that identifies the password file to use
308 private static final String PASSWORD_FILE_OPTION = "passwordFile";
309 private static final String HASH_PASSWORDS = "hashPasswords";
310
311 /**
312 * Creates an instance of <code>FileLoginConfig</code>
313 *
314 * @param passwordFile A filepath that identifies the password file to use.
315 * If null then the default password file is used.
316 * @param hashPasswords Flag to indicate if password file needs to be hashed
317 */
318 public FileLoginConfig(String passwordFile, String hashPasswords) {
319
320 Map<String, String> options;
321 if (passwordFile != null) {
322 options = new HashMap<String, String>(1);
323 options.put(PASSWORD_FILE_OPTION, passwordFile);
324 options.put(HASH_PASSWORDS, hashPasswords);
325 } else {
326 options = Collections.emptyMap();
327 }
328
329 entries = new AppConfigurationEntry[] {
330 new AppConfigurationEntry(FILE_LOGIN_MODULE,
331 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
332 options)
333 };
334 }
335
336 /**
337 * Gets the JAAS configuration for file-based authentication
338 */
339 public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
340
341 return name.equals(LOGIN_CONFIG_NAME) ? entries : null;
342 }
343
344 /**
|