Securing Tomcat
Tomcat is a great web server. Though for production there is
room for improvement.
There are some basic things that need to be done to make
your tomcat secure. Some of them are simple like changing the default shutdown
port to a different one. Others are simple but can be easily overlooked, like
removing the default demo application and removing the management interface.
For a list see: http://www.tomcatexpert.com/blog/2011/11/02/best-practices-securing-apache-tomcat-7.
Tomcat Users
If you want to use the tomcat manager application but what
to use users, tomcat supports defining roles and users in the tomcat-users.xml
file (see https://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html).
An example of this file is:
<tomcat-users>
<user
password="test"
roles="manager-gui,manager-status,manager-script,manager-jmx"
username="tomcat"/>
<role
rolename="admin"/>
</tomcat-users>
For the most part this is good enough, but what if you do
not want your password in clear text? Tomcat supports the option to use MD5
instead of the clear text. To do this in the server.xml file, in the Realm node,
you need to add the following:
<Realm
className="org.apache.catalina.realm.UserDatabaseRealm"
digest="md5" resourceName="UserDatabase"/>
JMX Login
Most applications need a JMX MBean for debugging and
monitoring. The JVM supports user name and password in the following way.
To your application you add the following JVM args:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8007
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.password.file={file_location}\jmxremote.password
-Dcom.sun.management.jmxremote.access.file={file_location}\jmxremote.access
You will need to change the ACL of the file for the
jmxremote.password else the solution will not work (http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html).
The problem is that the file with the password is still open
and not encrypted. To fix this we need to implement our own Login Module using
JASS (have a look at https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization).
The implement our own login module we need to change the JVM
args to:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8007
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.ext.dirs={dir_location}
-Dcom.sun.management.jmxremote.login.config=AMFConfig
-Djava.security.auth.login.config={file_location}\AMF.config
-Dcom.sun.management.jmxremote.access.file={file_location}\jmxremote.access
For the login to work, the user still needs to be in the
jmxremote.access file with the proper access level (readonly, readwrite).
We have added two new entries:
java.security.auth.login.config – this entirety will tell
the JVM to load the JASS configuration file, for example:
TestConfig {
plugin.com.tomcat.login.MyLoginModule Requisite passwordFile="\user\abc\jmxremote.access";
};
This will tell the JVM to use the class LoginModule for the
JASS login. Since the configuration file can have more than one definition, you
need to specific which module to use with: com.sun.management.jmxremote.login.config.
There are many tutorials for this (http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html,
https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization).
What they don’t write is that you need to create a separate jar
that includes your login module (plugin.com.tomcat.login.LoginModule). Once you
have this jar you need to put it in the java external folder. Adding it to the
classpath is not enough. No we usually don’t have access to the java external
folder, so since java 6 you can add another path for the external dir: java.ext.dirs.
This will load all default external jars and your login.
An example code for the login module is:
public class MyLoginModule implements LoginModule {
private Subject subject;
private CallbackHandler callbackHandler;
private Map<String, ?>
options;
private JMXPrincipal user;
private boolean succeeded = false;
public MyLoginModule() {
}
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,
?> sharedState, Map<String,
?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.options = options;
succeeded = false;
}
//function for map
private
Map<String,String> getUserPassword(String passwordFile){
Map<String,String>
map = new HashMap<String,
String>();
File
file = new File(passwordFile);
if (file.exists()) {
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
while (true) {
String
line = buffer.readLine();
if (line == null)
break;
String[]
fields = line.split("\\s+");
String
fileUser = fields[0];
String
filePassword = fields[1];
map.put(fileUser, filePassword);
}
}
catch (IOException e) {
return map;
}
}
else{
System.out.println("password file
not found: " + passwordFile);
}
return map;
}
public boolean validateUser(String passwordFile, String userName, String password) {
String
md5 = EncryptionHelper.md5(password);
Map<String,
String> userPasswords = getUserPassword(passwordFile);
String
filePassword = userPasswords.get(userName);
if (md5.equals(filePassword)) {
return true;
}
return false;
}
@Override
public boolean login() throws LoginException {
String
passwordFile = (String) options.get("passwordFile");
if (callbackHandler == null) {
throw new LoginException("Oops,
callbackHandler is null");
}
Callback[]
callbacks = new Callback[2];
callbacks[0] = new NameCallback("name:");
callbacks[1] = new PasswordCallback("password:", false);
try {
callbackHandler.handle(callbacks);
}
catch (IOException e) {
throw new LoginException("Oops,
IOException calling handle on callbackHandler");
}
catch
(UnsupportedCallbackException e) {
throw new LoginException("Oops,
UnsupportedCallbackException calling handle on callbackHandler");
}
NameCallback
nameCallback = (NameCallback) callbacks[0];
PasswordCallback
passwordCallback = (PasswordCallback)
callbacks[1];
String
name = nameCallback.getName();
String
password = new String(passwordCallback.getPassword());
user = new JMXPrincipal(name);
if (validateUser(passwordFile, name, password)) {
succeeded = true;
return succeeded;
}
else {
succeeded = false;
throw new
FailedLoginException("Wrong Login! Incorrect User or Password");
}
}
@Override
public boolean commit() throws LoginException {
subject.getPrincipals().add(user);
return succeeded;
}
@Override
public boolean logout() throws LoginException {
subject.getPrincipals().remove(user);
return false;
}
@Override
public boolean abort() throws LoginException {
return false;
}
}
Debugging
To debug the login you have a few options. The regular
attach process will work nicely and you can debug your login. In addition on
the server side you can add the following system parameter: -Djava.security.debug=all.
Also on the client side you can run the jconsole from the
command line with the following parameter:
Jconsole –debug. This will open a debug window and print the
errors from the server side.
obat susah buang air kecil
ReplyDeleteobat gatal di telapak tangan
obat benjolan di sekitar bibir vagina
obat herbal radang otak
obat herbal tetanus
obat tbc kronis
obat alami penyakit hernia
obat radang usus buntu
obat sakit perut
obat kadar gula darah rendah
obat radang usus besar