I am using the JConsole to access my application MBeans and i use the the password.properties file. But as per the Sun's specification this file contains passwords in clear text formats only.
com.sun.management.jmxremote.password.file=<someLocation>/password.properties
Now i would want to encrypt the password and use it for the JMX user authentication from JConsole (the username and password fields in Remote section). I could use any pre-defined encryption logic or my own encryption algorithms.
Does anyone know of any such interception to change the plain text password to encrypted one so that the JMX Framework too knows about the encrypted password?
My Current password file:
guest guest
admin admin
With Encryption it should look like:
guest ENC(RjqpRYbAOwbAfAEDBdHJ7Q4l/GO5IoJidZctNT5oG64=)
admin ENC(psg3EnDei6fVRuqHeLwOqNTgIWkwQTjI2+u2O7MXXWc=)
You can use the configuration parameter com.sun.management.jmxremote.login.config in the management.properties file (see %JAVA_HOME%/lib/management/management.properties) to configure which Authenticator and LoginModule to use.
The default is the following:
JMXPluggableAuthenticator {
com.sun.jmx.remote.security.FileLoginModule required;
};
which reads plain text password file jmxremote.password. Since the com.sun.jmx.remote.security.JMXPluggableAuthenticator can be reconfigured
to use any LoginModule implementation, you are free to either choose an existing LoginModule or to implement your own
which uses encrypted password files.
To reimplement FileLoginModule, you should have a look at the attemptAuthentication(boolean) method, which
actually performs the authentication and which you probably are going to replace. Implement the javax.security.auth.spi.LoginModule interface
and use the given CallbackHandler (you will get it from the init() method) to ask for a username and password. Encrypt/hash the received password and compare it against the one read from your encrypted password file. Pseudo code:
public class EncryptedFileLoginModule implements LoginModule {
#Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
}
public boolean login() throws LoginException {
attemptLogin();
if (username == null || password == null) {
throw new LoginException("Either no username or no password specified");
}
MessageDigest instance = MessageDigest.getInstance("SHA-1");
byte[] raw = new String(password).getBytes();
byte[] crypted = instance.digest(raw);
// TODO: Compare to the one stored locally
if (!authenticated) throw new LoginException();
return true;
}
private void attemptLogin() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("username");
callbacks[1] = new PasswordCallback("password", false);
callbackHandler.handle(callbacks);
username = ((NameCallback) callbacks[0]).getName();
user = new JMXPrincipal(username);
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);
((PasswordCallback) callbacks[1]).clearPassword();
}
However, as this is already the server-side, the password would afaik be still transferred in plain text if you don't enforce
JMX over SSL. So, either enforce SSL or use another transport protocol mechanism which encodes the credentials before
transmitting them over the wire.
To conclude, it's perhaps much better to rely on existing authentication mechanisms provided by JAAS. If, for example,
you're running in a local Windows environment, you can easily use the NTLoginModule for auto-login. But it only works on local machine.
Create a file c:/temp/mysecurity.cfg:
MyLoginModule {
com.sun.security.auth.module.NTLoginModule REQUIRED debug=true debugNative=true;
};
Next, configure the jmxremote.access file to contain the usernames or roles you wish to grant access to your JMX server:
monitorRole readonly
controlRole readwrite ...
mhaller readonly
(I recommend to enable debug mode until it works. You will see all the user names, domain names and group names when a user tries to log in)
Set the following JVM arguments for your server:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8686
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=true
-Djava.net.preferIPv4Stack=true
-Djava.security.auth.login.config=c:/temp/mysecurity.cfg
-Dcom.sun.management.jmxremote.login.config=MyLoginModule
Start up your application and try to connect using JConsole or VisualVM.
Note that JConsole, you will need to specify a username and a password, although it's not going to be used. Any password and any username will work.
The reason is because jconsole will try to authenticate with null username and null password, which is blocked explicitly.
VisualVM does a better job by using empty strings for username and password when none are entered by the user.
Also note that the NTLoginModule does not work when connecting remotely, i think you would have to use a more sophisticated login module,
but Sun already provides enough of them:
com.sun.security.auth.module.Krb5LoginModule: Authenticates users using the Kerberos protocols
com.sun.security.auth.module.LdapLoginModule: (new in Java 6): Performs authentication against an LDAP server by specifying technical connection user
com.sun.security.auth.module.JndiLoginModule: Performs authentication against an LDAP server registered in the JNDI context
com.sun.security.auth.module.KeyStoreLoginModule: Authenticates users by using a Java Keystore. Supports PIN or smart card authentication.
You will want to have a look at the LdapLoginModule
Related
I am trying to implement a feature for a user to change their password in their settings page when they are logged in, and I require the user's old password as well as the new password when they try to change it as an extra security measure. My problem is that I cannot find a way to verify if the user's old password is correct. Is there an easy way to do this?
I receive the entered form inputs on the server so the solution would have to be on the backend (node.js)
Many thanks
Though the accepted solution works, there is also a way to verify a user's password from the backend, using the Google Identity Kit REST API's "verifyPassword" endpoint (which has recently been renamed to "signInWithPassword", but works exactly the same):
HTTP POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[YOUR_FIREBASE_API_KEY]
{
email,
password,
}
If that endpoint doesn't return an error, that means the password is valid.
See this thread for more information.
You have to do it client side. This is not an operation that the admin SDK is designed to handle. You will ask the current user for the password and reauthenticate with it and then update password:
const cred = firebase.auth.EmailAuthProvider.credential(
firebase.auth().currentUser.email, oldPass);
firebase.auth().currentUser.reauthenticateWithCredential(cred)
.then(() => {
return firebase.auth().currentUser.updatePassword(newPass);
})
.catch((error) => {
// Some error.
});
I use Java NIO secured by SSL to connect client and server. To connect to a server the user is prompted to enter host, port, username and password. So far I can connect client and server (they successfully complete their SSL handshake) and I could theoretically start sending data back and forth. I have not written a mechanism to verify login credentials (username, password) yet.
The server can authenticate username and password by looking them up in a database. If the credentials a client sends are incorrect, the connection will be closed.
Question 1: When should the credentials be validated? I assume this has to happen after the SSL handshake.
Question 2: How do I securely package the credentials before they are serialized and sent to the server? I assume I should hash the password. Should I hash the username too?
Would something simple like this suffice?
public class LoginCredentials implements Serializable {
private static final long serialVersionUID = 1026410425432118798L;
private final String username;
private final byte[] passwordHash;
public LoginCredentials(String username, byte[] passwordHash) {
this.username = username;
this.passwordHash = passwordHash;
}
public final String getUsername() {
return username;
}
public final byte[] getPasswordHash() {
return passwordHash;
}
}
Question 3: Authenticating credentials should be done once per session, correct? I read some posts that seemed to indicate the credentials should be verified for every request.
Question 4: Which hashing algorithm should I use? SHA–512 seems to be very popular.
of course that after ssl handshake, when the ssl connection is established, this makes it more secure
Not many applications really do that, most of them just sends the password over ssl not hashing it at all. Yes, you can generate a hash, but the hash should be generated for every login, so it will not be always the same, this requires some code on client side to resolve some challenge which includes the correct password and some random thing sent by server, otherwise it would not differ much from regular password authentication. But there is plenty of authentication mechanisms - passwords, hashes, tokens, ssl certificates to name a few.
you need to check if the authenticated user has access rights to the resource He tries to access - this is for every request, not to login the user for every request if you have session. If you need to manage the user access rights to grant or revoke access during single session then you need to read the user access rights for every request, if you don't need such granularity then reading them once for the whole session is ok. Sometimes there are sessionless services eg. some REST, then typically you need to send some credentials on every call.
You can use any hashing algorithm that's not too easy to decipher.
I am building a web application with java and using JDBC driver
please tell me if i wrong, i dont think using this block of code is secured
how should i make it secured without using "HARD CODED" password
Connection connection = null;
connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:mkyong","username","password");
connection.close();
taken from:
http://www.mkyong.com/jdbc/connect-to-oracle-db-via-jdbc-driver-java/
If you're building a web-app your resources should be declared externally, for example in a Tomcat Context.xml file. The password will be located there, not in your code. And keeping that secure is a matter of physical security.
Java code will be executed on the server if you mean a Tomcat web application for example. So it should be ok so.
But if you want to have more security you could create a credentials.properties file, with tomcat as owner and rights of 600. Then you read username and password from that file.
And of course you could encrypt it in the file.
EDIT: And the credentials.properties file should not be accessable over the web ;)
Try Jasypt and it should help:
http://jasypt.org/
Example (Using a .properties file mechanism):
Step1: Find out encrypted password and make a note of it for usage:
StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
Let's say the encryptedPassword is: G6N718UuyPE5bHyWKyuLQSm02auQPUtm
Step2: Store DB connection credentials in a .properties file with encrypted password
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://localhost/reportsdb
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
Step3: How do we read this value? like this:
/*
* First, create (or ask some other component for) the adequate encryptor for
* decrypting the values in our .properties file.
*/
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt"); // could be got from web, env variable...
/*
* Create our EncryptableProperties object and load it the usual way.
*/
Properties props = new EncryptableProperties(encryptor);
props.load(new FileInputStream("/path/to/my/configuration.properties"));
/*
* To get a non-encrypted value, we just get it with getProperty...
*/
String datasourceUsername = props.getProperty("datasource.username");
/*
* ...and to get an encrypted value, we do exactly the same. Decryption will
* be transparently performed behind the scenes.
*/
String datasourcePassword = props.getProperty("datasource.password");
// From now on, datasourcePassword equals "reports_passwd"...
For decrypting the encrypted value, we just had to access it with getProperty, just as with any other non-encrypted value.
Details here: http://www.jasypt.org/encrypting-configuration.html
I have a Java EE application that uses JDBCReal as JAAS Context for authentication on GlassFish 3.1. And below is the authentication code in a JSF2.0 managedbean -
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
if (request.getUserPrincipal() != null) {
request.logout();
}
if (request.getUserPrincipal() == null) {
request.login(this.username, this.password);
}
I am trying to add some admin functionalities (like create/delete/update/disable user). I am almost done with all of them except for the "disable" one, which is confusing me on how to proceed.
The only way that I can think of right now is to add a field, something like "status", in the "users" table, which will have a value ("enabled" or "disabled"). And check that "status" before doing the authentication.
Is that how I should do it considering that I am using JAAS (JDBCRealm)? Or, is there some other (standard) way?
I am trying to see, if there is someone here who has some experience in this area and can point me towards the right direction.
I suppose you manage your users table through JDBC/JPA.
In unix/linux the passwd -l change the hash to an invalid value. From man passwd:
-l This option is used to lock the specified account and it is
available to root only. The locking is performed by rendering
the encrypted password into an invalid string (by prefixing the
encrypted string with an !).
In practice an unlocked account from /etc/shadow:
test:$6$c7Lz2A2l$8AoSBy8C2U7uUns4aDRP2J/QRzUOYF...o69XPR/:15259:0:99999:7:::
And the same account after passwd -l test:
test:!$6$c7Lz2A2l$8AoSBy8C2U7uUns4aDRP2J/QRzUOYF...o69XPR/:15259:0:99999:7:::
The prefixed value is invalid because hash functions always return the same number of bits. If your stored value is longer than that length they will never match. You can do the same with your hashed passwords - just prefix the password with an ! (or any other string) through JDBC/JPA.
Of course this does not work with plaintext passwords.
Another solution is removing the user's roles from the database. In this case the user could login but if you set up the security-constraints well in the web.xml the user wouldn't be able to do anything (except logout).
I have an Ldap directory synchronised from a microsoft active directory.
This Ldap contain many account, each account have a password attribute.
I must develop a java program where a user have to log with his AD login and password, but i don't know the method employed to correctly encrypt the password typed.
I need it to compare with the ldap password.
I also need to bind new account with the same password encryption.
Anyone know how to do?
Well first of all you can use a BIND with SSL, but that's considered kind of the lame way to go about it and may be disabled on some systems. A truly secure way is using SPNEGO-GSS, and this is not trivial. You have to learn and understand about Kerberos. That's a long topic but you can start with reading and going through everything here
I've found the solution with spring,
here the method to test login/pass couple :
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("cn", login));
boolean authentifie = ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);