Add information to the subject on apache shiro - shiro

Im using apache shiro. When i want to know if the user have permissions and roles i use SecutiryUtils.getSubject(). I like to know how to add more information to the subject like email, primary key and any other business information that i need so i can retrieve that information when necessary.
This is my shiro.ini:
[main]
ds = org.apache.shiro.jndi.JndiObjectFactory
ds.requiredType = javax.sql.DataSource
ds.resourceName = java:/comp/env/jdbc/myDS
# JDBC realm config
jdbcRealm = com.mycompany.JdbcRealmImpl
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = SELECT password FROM user WHERE username = ? AND status = 1
jdbcRealm.dataSource = $ds
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher
[urls]
/logout = logout
/** = authcBasic
This is my JdbcRealm
public class JdbcRealmImpl extends JdbcRealm {
public JdbcRealmImpl() {
super();
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(
final AuthenticationToken token) throws AuthenticationException {
final AuthenticationInfo info = super.doGetAuthenticationInfo(token);
// create a user to test
final User user = new User();
user.setId(11111);
return new SimpleAuthenticationInfo(user, info.getCredentials(),
getName());
}
}
And here is the code where i try to retrieve the user info.
final Subject currentUser = SecurityUtils.getSubject();
final User user = (User) currentUser.getPrincipal();
// null
System.out.println(user);

You should just put that in a database and retrieve it using the Subjects username (for example an emailaddress).

Related

Keycloak Admin API - How to check if password fits the password policy

I am using Keycloak admin API to create a new user.
How can I check that the given password indeed fits the realm password policy before creating the user?
I am using the following code:
Response response = usersResource.create(userRepresentation);
String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
UserResource userResource = usersResource.get(userId);
CredentialRepresentation passwordCred = new CredentialRepresentation();
passwordCred.setTemporary(false);
passwordCred.setType(CredentialRepresentation.PASSWORD);
passwordCred.setValue(somePassword);
userResource.resetPassword(passwordCred);
The problem with the above code is that the method "resetPassword" fails if the given password does not fit the password policy, but at this point the user has already been created in keycloak, and I have to delete it, since I have no way to "rollback".
The other option is to check is the password is OK before creating the user. But how can I do it?
You will get validation failure message as JSON Object some thing like this
{"error":"invalidPasswordMinLengthMessage","error_description":"Invalid password: minimum length 8."}
I used following code to read the validation failure message from the ClientErrorException
public void resetUserInvalidPassword() {
String userId = createUser("user1", "user1#localhost");
try {
CredentialRepresentation cred = new CredentialRepresentation();
cred.setType(CredentialRepresentation.PASSWORD);
cred.setValue(" ");
cred.setTemporary(false);
realm.users().get(userId).resetPassword(cred);
} catch (ClientErrorException e) {
Response response = e.getResponse();
System.out.println(getErrorMessage(response));
response.close();
}
}
private String getErrorMessage(Response response) {
Object entity = response.getEntity();
String errorMessage = "(none)";
if (entity instanceof ErrorRepresentation)
errorMessage = ((ErrorRepresentation) entity).getErrorMessage();
else if (entity instanceof InputStream)
errorMessage = new BufferedReader(new InputStreamReader((InputStream)entity)).lines().collect(Collectors.joining("\n"));
else if (entity != null)
errorMessage = entity.toString();
return errorMessage;
}
UserResource has the getUsers() method to find a user by username and check its attributes.
If the resetPassword failed, you could find the user, apply checks if needed, and resetPassword again.

Apache shiro remember me not working

Im trying to use the rememberme feature from apache shiro, but its not working.
I have this shiro.ini
[main]
ds = org.apache.shiro.jndi.JndiObjectFactory
ds.requiredType = javax.sql.DataSource
ds.resourceName = java:/comp/env/jdbc/myDS
# JDBC realm config
jdbcRealm = br.com.myproject.web.service.security.JdbcRealmImpl
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = SELECT password FROM user WHERE username = ? AND status = 1
jdbcRealm.dataSource = $ds
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher
securityManager.realms = $jdbcRealm
[urls]
/** = authcBasic
This is my JdbcRealmImpl:
public class JdbcRealmImpl extends JdbcRealm {
public JdbcRealmImpl() {
super();
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(
final AuthenticationToken token) throws AuthenticationException {
final AuthenticationInfo info = super.doGetAuthenticationInfo(token);
final UserDB userDB = new UserDB();
final User user = userDB.getUserByUsername((String) token.getPrincipal());
return new SimpleAuthenticationInfo(user, info.getCredentials(), getName());
}
}
Since this is a web service project i have a login service:
#POST
#Path("/login")
public Response login(#FormParam("username") final String username, #FormParam("password") final String password, #FormParam("remember") final boolean remember) {
final Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
final UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
token.setRememberMe(remember);
currentUser.login(token);
} catch (final AuthenticationException e) {
return Response.status(Status.BAD_REQUEST).entity("Invalid user").build();
}
}
return Response.ok().build();
}
The problem is that SecurityUtils.getSubject().isRemembered() always return false even when i set token.setRememberMe(true);
Is there any configuration that im missing?
Subject.isRemembered() is a little tricky in Shiro. It only returns true if the Subject has a valid Remember Me setting (cookie, etc) AND the Subject is not Authenticated. Details here: http://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/subject/Subject.html#isRemembered()
So, I suspect that your Remember Me is working fine, but your expectations for Subject.isRemembered() doesn't match what the method actually does.
Actually if you logout from your application throught shiro logout remember me will be erased. To try make session time out just one minute let session expire itself and reload main page now you will find that user is actually being remembered. LOGOUT CLEARS REMEMBER ME.
If you want to use remember me still after logout you can try to extend securitymanager and use this securitymanger for your application.
public class CustomSecurityManager extends DefaultWebSecurityManager {
#Override
protected void beforeLogout(Subject subject)
{
super.removeRequestIdentity(subject);
}
}

Apache Shiro Authentication with Facebook OAuth

I am stucked in authenticating my application running on Shiro with Facebook OAuth. I really don't know what am I doing wrong. Bascially, my problem is when I get a "code" from Facebook. I want shiro to authenticate it using that code.
This is my authentication code.
FacebookToken token = null;
try{
org.apache.shiro.subject.Subject currentUser = SecurityUtils.getSubject();
//currentUser.logout();
//This is done to avoid temporary multiple url hit.., when the user is not logged out
token = new FacebookToken(code);
currentUser.login(token); //returns true if valid
result = true;
}catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
// ... catch more exceptions here (maybe custom ones specific to your application?
catch (AuthenticationException ae) {
log.info("Authentication exception Here.");
}
Here is my facebook token class:
public class FacebookToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String code;
public FacebookToken(){
}
public FacebookToken(String code){
this.code = code;
}
public Object getCredentials() {
return null; //Credentials are handled by facebook
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Object getPrincipal() {
return null; //Not known facebook does the login
}
I have the realm for facebook that is extending authorization realms.
public class FacebookRealm extends AuthorizingRealm {
}
and finally here is my shiro.ini file:
[main]
#authc.loginUrl = /login
#authc.successUrl = /hello
#logout.redirectUrl = /hello
# ------------------------
# Database
# Own Realm
jdbcRealm = com.shiro.common.controller.MyCustomRealm
facebookRealm = com.facebook.login.FacebookRealm
# Sha256
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
# base64 encoding, not hex in this example:
sha256Matcher.storedCredentialsHexEncoded = false
sha256Matcher.hashIterations = 1024
#Facebook Credential matcher
fbCredentialsMatcher = com.facebook.login.FacebookCredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher
facebookRealm.credentialsMatcher = $fbCredentialsMatcher
# User Query
# default is "select password from users where username = ?"
jdbcRealm.authenticationQuery = SELECT password, salt FROM User WHERE email = ?
# permissions
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.userRolesQuery = select roleName from UserRole where email = ?
jdbcRealm.permissionsQuery = select permission from RolesPermission where roleName = ?
# Connection
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = root123
ds.databaseName = testdb
jdbcRealm.dataSource=$ds
#authc.usernameParam = email
#authc.passwordParam = password
#authc.failureKeyAttribute = shiroLoginFailure
# Use Built-in Chache Manager
builtInCacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $builtInCacheManager
#securityManager.realms = $facebookRealm,$jdbcRealm
securityManager.realms = $facebookRealm
# -----------------------------------------------------------------------------
[urls]
#/hello = authc
#/login = authc
#/admin.jsp = authc, perms["admin:access"]
Now when do i debug and reach at currentuser.login methods and go inside, it throws an exception saying
Realm [FacebookRealm#52039826] does not support authentication token [FacebookToken#132d9844]. Please ensure that the appropriate Realm implementation is configured correctly or that the realm accepts AuthenticationTokens of this type.
Please suggest me whether am I doing correct, or not !! Am i missing any configuration or any thing else. Thank you !!
You should extend your FacebookRealm with the following method:
#Override
public boolean supports(AuthenticationToken token) {
return token instanceof FacebookToken;
}
or add the following line to your ini:
facebookRealm.authenticationTokenClass=<realpackage>.FacebookToken

OAuthRequestValidator Access Token and Access Token Secret

I am trying to add an account to QuickBooks Online using Intuit IPP:
https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0200_DevKits_for_Intuit_Partner_Platform/0100_IPP_.NET_DevKit/Query_Filters/QuickBooks_Online
How do I get the access token and the access token secret? Here is my code:
class Program
{
static string appToken = "xxx";
static string oAuthConsumerKey = "xxx";
static string oAuthConsumerSecret = "xxx";
static void Main(string[] args)
{
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(appToken, "", oAuthConsumerKey, oAuthConsumerSecret);
ServiceContext context = new ServiceContext(oauthValidator, appToken, "1234", IntuitServicesType.QBD);
DataServices dataServices = new DataServices(context);
Account account = new Account();
account.Desc = "TEST PLEASE DELETE";
string guid = Guid.NewGuid().ToString("N");
guid = guid.Substring(0, 30);
account.Name = guid;
account.Type = Intuit.Ipp.Data.Qbd.AccountTypeEnum.Liability;
account.TypeSpecified = true;
account.Subtype = "Accounts Payable";
Account resultAccount = dataServices.Add(account) as Account;
}
}
I figured it out. Look at step 6 here:
http://ippblog.intuit.com/blog/2012/09/ode-to-oauth-and-rest-apis-and-how-i-love-thee-not.html
Joseph,
For Future reference and for others the documentation for your question is located here:
IPP Oauth Documentation
regards,
Jarred

EclipseLink JPA username/password Lookup deletes record on running the app

I am using apache shiro to authenticate a user and i want to simply print the username out to my console to check if my finder function is working properly, it seems as when i add a record to the user (using a sql statement and not eclipseLink, the record is deleted when the application is run ?)
Here is how i am trying to retrieve a single user by username:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
Map<String, String> map = new HashMap<String, String>();
String tempUsername = token.getUsername();
String password = "";
Users user;
// Null username is invalid
if (tempUsername == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
AuthenticationInfo info = null;
// this will query and find the users by the specified username and then return us the single result
user = getAuthorizedUser(Users.findUsersesByUsernameEquals(tempUsername));
System.out.print(user.getUsername());
System.out.println("yea the username = ");
password = user.getPassword();
info = buildAuthenticationInfo(tempUsername, password.toCharArray());
return info;
}
/*Build the required authentication info; Replace with SaltAuthenticationInfo for salted passwords*/
protected AuthenticationInfo buildAuthenticationInfo(String username, char[] password) {
return new SimpleAuthenticationInfo(username, password, getName());
}
protected Users getAuthorizedUser(TypedQuery<Users> q){
System.out.println("working authentication");
return q.getSingleResult();
}
Is this because i am not using JPA to persist and add the user but rather writing a sql statement outside my application?
I disabled this property <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
This was deleting my test records and solved my problem.