Authentication trouble with Apache Shiro - java

I'm a beginner with Apache Shiro. I've been following the docs and lots of other tutorials, blogs etc. but I just can't get the authentication to work. When I attempt to login with a valid username and password, I always get an InvalidCredentialsException thrown. I'm using DynamoDB as a custom realm for storing user credentials, but I really don't think that matters. It's obviously the way that I'm storing and/or doing the credential matching that's not correct. Here's my setup:
Shiro.ini:
[main]
myRealm = com.enki.closing.users.DynamoDBRealm
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024
myRealm.credentialsMatcher = $credentialsMatcher
Create user account:
String password = ...
ByteSource passwordSalt = new SecureRandomNumberGenerator().nextBytes();
String hashedPasswordBase64 = new Sha256Hash(password, passwordSalt, 1024).toBase64();
// store the hashedPassword and salt in DynamoDB...
// I've tried storing the salt with and without base64 encoding.
The password and salt are stored fine in DynamoDB, the values look alright. Here's the custom realm for authentication:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken userPass = (UsernamePasswordToken) token;
String username = userPass.getUsername();
...
// pull the matching password and salt out of DynamoDB, no problems...
ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
return new SimpleAuthenticationInfo(username, passwordHash, passwordSalt, getName());
}
This is all pretty much what the docs are telling me to do, but there's something not right. When I try the login, it get InvalidCredentialsException.

I figured out how to get it working. I had to change this (in my custom realm impl):
ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
to this:
ByteSource passwordSalt = ByteSource.Util.bytes(
Base64.decode( storedPasswordSalt) );

Related

What is the best method to secure requests based on an Active Directory authentication solution

I have a problem for a backend solution developpement. I need someone to guide me.
I'm developping a backend solution with SpringBoot.
My backend should :
Connect to an Active Directory
Use a token system for the security part
Give special access for each request (based on AD group)
After a lot of tests and research, I already have this :
Connect to an Active Directory
For the connection to AD part, I did this :
Inside a class that extends WebSecurityConfigurerAdapter
#Override
public void configure(AuthenticationManagerBuilder auth) {
ActiveDirectoryLdapAuthenticationProvider adProvider
= new ActiveDirectoryLdapAuthenticationProvider("domain.com", "ldap", "ou,dc");
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
adProvider.setUserDetailsContextMapper(userDetailsContextMapper());
auth.authenticationProvider(adProvider);
}
userDetailsContextMapper() simply maps the info to an user class that contains the username, the lastname and the list memberOf of the user (AD groups).
Using token
I use this method for the token. It works too.
public SignedJWT getToken(String username) {
JWSSigner signer = null;
SecureRandom random = new SecureRandom();
byte[] sharedSecret = new byte[32];
random.nextBytes(sharedSecret);
signer = new MACSigner(sharedSecret);
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject(username)
.issuer("domain")
.expirationTime(new Date(new Date().getTime() + 60 * 1000))
.build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
signedJWT.sign(signer);
String serializedToken = signedJWT.serialize();
return signedJWT;
}
Access per request
For the third part I want to give access to a specific request only for a given AD group.
Imagine I have two correctly mapped request :
domain.com/sales/2022/all : Return all the sales values for the year 2022
domain.com/IT/inventory/all: Return all the IT inventory
I want only the people that are from the group IT that can get a result from the IT's request and for the sale's request, only someone who is a member of the groupe sales.
But first of all, I want only people who are authenticated and have a valid token who can call a request.
I searched and tested different solutions on the internet but I did not find anything compatible with my two previous method.
Can you help me ? I'm not specially looking for a solution, a link to a good documentation or some example are enough for me.

Do I Need to Hash My Passwords for Keycloak Client?

I'm using org.keycloak:keycloak-admin-client:12.0.4. I've been doing some research about how to use the API.
Here are a couple examples:
// ----
// Getting a JWT
// ----
Keycloak keycloak = KeycloakBuilder.builder()
.serverUrl("http://localhost:8180/auth")
.grantType(OAuth2Constants.PASSWORD)
.realm("dev")
.clientId("example-client")
.clientSecret("1169ef64-ea8f-47eb-9e55-74fdda9ee398")
.username("user1")
// raw password
.password("user1Pass")
.resteasyClient(
new ResteasyClientBuilderImpl()
.connectionPoolSize(10).build()
).build();
AccessTokenResponse atr =
keycloak.tokenManager().getAccessToken();
// ----
// Creating a new user
// ----
UserRepresentation user = new UserRepresentation();
user.setEnabled(true);
user.setUsername("tester1");
user.setFirstName("First");
user.setLastName("Last");
user.setEmail("example#email.com");
user.setAttributes(Collections.singletonMap("origin", Arrays.asList("demo")));
RealmResource realmResource = keycloak.realm("dev");
UsersResource usersRessource = realmResource.users();
Response response = usersRessource.create(user);
String userId = CreatedResponseUtil.getCreatedId(response);
CredentialRepresentation passwordCred = new CredentialRepresentation();
passwordCred.setTemporary(false);
passwordCred.setType(CredentialRepresentation.PASSWORD);
// raw password
passwordCred.setValue("test");
UserResource userResource = usersRessource.get(userId);
So in both of these situations, I'm using a String which is the raw password. My question is, should I be hashing passwords before sending them to Keycloak?
It's not that I distrust Keycloak, I'm just curious if Keycloak itself is doing some hashing in its own implementation. I've done some searching on Google, but haven't found any what I'm looking for.

OpenText LiveLink : How can use ImpersonateUser function?

I'd like to have from an admin user the context of the current loggin user.
For that, I use the admin token to have the current one with the function impersonateUser() because I don't have the password of the user.
I have the following error when I call the impersonateUser() on the Authentication object :
javax.xml.ws.soap.SOAPFaultException: OTDS username and password are required.
Here my example :
URL authLocation = new URL("http://localhost:8080/les-services/services/Authentication?wsdl");
String aToken = WebServiceUtil.getAuthenticationToken(authLocation, username, password);//admin token
OTAuthentication fOTAuth = new OTAuthentication();
fOTAuth.setAuthenticationToken(aToken);
com.opentext.livelink.service.core.Authentication auth = webServiceUtil.getAuthenticationService(authLocation);
String token = auth.impersonateUser(newUser);
fOTAuth.setAuthenticationToken(token);
I also found a class ImpersonateUser but I don't know how to use it :
ImpersonateUser impUser = new ImpersonateUser();
impUser.setUserName(newUser);
Do you have any advice ?
Thanks !
Here are the docs for the ImpersonateUser() method.

Smack login with md5 hashed password to Openfire

How can I login with MD5 hashed password to openfire?
I'm using smack 4.0.4.
I've tried DIGEST-MD5 registiration but it's not work
SASLAuthentication.registerSASLMechanism("DIGEST-MD5", SASLDigestMD5Mechanism.class);
SASLAuthentication.supportSASLMechanism("DIGEST-MD5");
I'm getting this error :
SASLError using PLAIN: not-authorized
My code looks like this:
config = new ConnectionConfiguration(xmppServerAddress, Integer.parseInt(xmppServerPort));
config.setDebuggerEnabled(true);
config.setReconnectionAllowed(true);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
XMPPTCPConnection connectionTmp = new XMPPTCPConnection(config);
connectionTmp.connect();
connectionTmp.login("username","md5hashedpassword");
I have a similar problem, you could check if your password is in md5.
I have generate a passwords from the userid (long type) as:
#Override
public String generatePassword(long userId) {
String userIdString = String.valueOf(userId);
return MD5util.getMD5(userIdString + StringUtil.getStringAlternateCharacters(userIdString));
}
or find out that your xmpp server (openfire) IP is correctly configured as you wish to login.

How to stock and use a shiro's salt from database

I use shiro in application for the authenticate. I use hashed password with a salt and I store them in my database like this :
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
String strSalt = byteArrayToHexString(byteTabSalt);
String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 1024).toBase64();
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
I store the salt with a String in my database. Now in my realm I want to get back my datas from the database, I use a transactionnal service for this. But my salt is a Strong so I want it to turn back as ByteSource type with the static method :
ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String
But when I create my SaltedAuthenticationInfo it doesn't auth.
I think my problem is from my convert method :
private String byteArrayToHexString(byte[] bArray){
StringBuffer buffer = new StringBuffer();
for(byte b : bArray) {
buffer.append(Integer.toHexString(b));
buffer.append(" ");
}
return buffer.toString().toUpperCase();
}
Thanks for your help.
As mentioned in the excellent answer https://stackoverflow.com/a/20206115/603901, Shiro's DefaultPasswordService already generates unique salts for each password.
However, there is no need to implement a custom PasswordService to add a private salt (sometimes called "pepper") to the per-user salts. Private salt can be configured in shiro.ini:
[main]
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code
hashService.privateSalt = myVERYSECRETBase64EncodedSalt
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
passwordMatcher.passwordService = $passwordService
Java code for generating a matching password hash:
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(HASH_ITERATIONS); // 500000
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded.
hashService.setGeneratePublicSalt(true);
DefaultPasswordService passwordService = new DefaultPasswordService();
passwordService.setHashService(hashService);
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser");
The resulting hash looks like this:
$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs=
The private salt is not stored in the database, which makes it harder to crack the passwords if an adversary gains access to a database dump.
This example was created using shiro-1.2.2
Thanks to https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini for help with the syntax for shiro.ini
Have you looked at PasswordMatcher / PasswordService?
This already has all of the encoding/decoding/compare logic built-in. To use it:
Storing password in database:
PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
String hashedPasswordBase64 = service.encryptPassword(inPassword);
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
Then you can simply use PasswordMatcher as the matcher in your realm.
realm.setCredentialsMatcher(new PasswordMatcher());
or in shiro.ini:
matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher
The DefaultPasswordService implementation automatically adds a random salt to each encryptPassword call. That "public" salt will be stored within the "hashedPasswordBase64" that you receive from "encryptPassword".
Because the "public" salt is individually generated for each hashed password one cannot "simply" generate a rainbow table and brute-force all your hashed passwords at once. For each hashed password the attacker would have to generate an own, unique rainbow table because of the unique "public" salt. So far you do not need to put an extra salt into the database.
To make your stored hashed passwords even more secure you can furthermore add a "private" salt that should be stored anywhere else - as long as not in the database. By using a "private" salt you could protect the hashed passwords against a brute-force rainbow-table attack, because the attacker does not know the "private" salt and cannot gain the "private" salt from the database entries.
This is a very basic example how to create a PasswordService that utilizes a "private" salt provided as a constant string and that works as CredentialsMatcher:
public class MyPrivateSaltingPasswortService extends DefaultPasswordService
{
public MyPrivateSaltingPasswortService()
{
super();
HashService service = getHashService();
if (service instanceof DefaultHashService)
{
((DefaultHashService) service).setPrivateSalt(
new SimpleByteSource("MySuperSecretPrivateSalt"));
}
}
}
you then could use your own implementation in shiro.ini:
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
This example was created using shiro-1.2.2
I change my type for the save of my salt. Now I'm using a byte[] instead of a String.
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
And I stock the byteTabSalt in my database.

Categories

Resources