I've created an application and been using Shiro for the authentication.
I've followed most of the guides and also some of the posted questions here regarding shiro and Jdbc Realm.
Here is my shiro.ini file:
[main]
authc.loginUrl=/jsp/loginForm.jsp
authc.successUrl=/test/successUrl.jsp
authc.rememberMeParam = login-remember-me
logout.redirectUrl=/index.jsp
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
hashService.privateSalt = someBase64EncodedSaltValue
realm = org.apache.shiro.realm.jdbc.JdbcRealm
realm.permissionsLookupEnabled = false
realm.authenticationQuery = SELECT password FROM userTable WHERE username = ?
ps = org.apache.shiro.authc.credential.DefaultPasswordService
ps.hashService = $hashService
pm = org.apache.shiro.authc.credential.PasswordMatcher
pm.passwordService = $ps
jof = org.apache.shiro.jndi.JndiObjectFactory
jof.resourceName = java:comp/env/jdbc/theResourceName
jof.requiredType = javax.sql.DataSource
jof.resourceRef = true
realm.dataSource = $jof
realm.credentialsMatcher = $pm
securityManager.realms = $realm
and i'm using the following code in Java to save the password in the database:
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(500000);
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
hashService.setPrivateSalt(new SimpleByteSource(
"someBase64EncodedSaltValue")); // Same salt as in shiro.ini, but NOT
// base64-encoded.
hashService.setGeneratePublicSalt(true);
DefaultPasswordService pwService = new DefaultPasswordService();
pwService.setHashService(hashService);
this.password = pwService.encryptPassword(password);
Everything looks good and is saving as expected but the problem is when I am logging in. I've traced the execution to JdbcRealm.class and I've seen that the value compared is the "raw string password" and the encrypted password from the database.
Did I miss any step configuring?
To use Salted its better to have seperate salt for every user. So store that salt in database. SEE
Now,
Extend org.apache.shiro.realm.jdbc.JdbcRealm like:
package common.shiro;
import org.apache.shiro.realm.jdbc.JdbcRealm;
public class JDBCSaltedRealm extends JdbcRealm {
public JDBCSaltedRealm() {
setSaltStyle(SaltStyle.COLUMN);
}
}
In shiro.ini:
credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=SHA-256
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 500000
credentialsMatcher.hashSalted = true
realm = common.shiro.JDBCSaltedRealm
realm .permissionsLookupEnabled = true
realm .authenticationQuery = SELECT password,salt FROM userTable WHERE username = ?
realm .dataSource = $jof
realm .credentialsMatcher = $credentialsMatcher
securityManager.realm = $realm
Related
I am in the process of creating a login system.
I use python flask and as database the Prostgresql.
I think I just store the hash value wrong.
I have saved it as vachar 255 so far
My code:
from flask import Flask, render_template, redirect, request, url_for, session
from flask_sqlalchemy import SQLAlchemy
import bcrypt
import psycopg2
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:PostGreSQL_13#localhost/test'
sql = SQLAlchemy(app)
#app.route('/')
def home():
return render_template("home.html")
#app.route('/register', methods=["GET","POST"])
def register():
if request.method == "GET":
return render_template("register.html")
else:
name = request.form['name']
email = request.form['email']
password = request.form['password'].encode('utf-8')
hash_password = bcrypt.hashpw(password, bcrypt.gensalt())
t_host = 'localhost'
t_port = "5432"
t_dbname = "test"
t_user = "postgres"
t_pw = "password"
db_conn = psycopg2.connect(host=t_host, port=t_port, dbname=t_dbname, user=t_user, password=t_pw)
db_cursor = db_conn.cursor()
db_cursor.execute("INSERT INTO users (UserName,UserEmail,UserPassword) VALUES (%s,%s,%s)",(name,email,hash_password,))
db_conn.commit()
session['name'] = name
session['email'] = email
return redirect(url_for("home"))
#app.route('/login', methods=["GET","POST"])
def login():
if request.method == "POST":
email = request.form['email']
password = request.form['password'].encode('utf-8')
t_host = 'localhost'
t_port = "5432"
t_dbname = "test"
t_user = "postgres"
t_pw = "password"
db_conn = psycopg2.connect(host=t_host, port=t_port, dbname=t_dbname, user=t_user, password=t_pw)
db_cursor = db_conn.cursor()
db_cursor.execute("SELECT username, useremail, userpassword FROM users WHERE useremail=%s",(email,))
user = db_cursor.fetchone()
db_conn.close()
if len(user) > 0:
name = user[0]
if bcrypt.hashpw(password, user[2].encode('utf-8')) == user[2].encode('utf-8'):
session['name'] = user[0]
session['email'] = user[1]
return render_template("home.html")
else:
return "Versuch es doch Nochmal"
else:
return render_template("login.html")
#app.route('/logout')
def logout():
session.clear()
return render_template("home.html")
if __name__ == '__main__':
app.secret_key = '012#!ApaAjaBoleh)(*^%'
app.run(debug=True)
the procedure I got from the Youtube video. see attachment.
I need a login system and this was recommended to me, it works pretty good.
The last one has to work somehow and if it works I would be very happy.
Can anyone tell me what I'm doing wrong or if my appendix with the database is right or wrong?
I know nothing about this language you're using, but any bcrypt implementation will output a string similar to:
$2a$12$ieXy2Rj/TEGqVRx0JihGFesujNFCdmlQWpUaTNvwQ0XuB3lzOcTWK
Yes, you should store that varchar string in your database.
I have been using JdbcRealm for shiro authentication and authorization, which has been working perfectly. My shiro.ini looks like this:
[main]
authc = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
logout = org.apache.shiro.web.filter.authc.LogoutFilter
authc.loginUrl = /login.xhtml
authc.successUrl = /index.xhtml
logout.redirectUrl = /login.xhtml
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery = select password from useraccount where active = true and username LIKE ?
jdbcRealm.userRolesQuery = select rolename from role where id in(select roleid from userrole where useraccountid = (select id from useraccount where username LIKE ?) and active = true) and active = true
ds = org.postgresql.jdbc2.optional.SimpleDataSource
ds.serverName = dbhost:5432
ds.user = db_user
ds.password = db_pass
ds.databaseName = db_name
jdbcRealm.dataSource = $ds
#.
#.
#.
jdbcRealm.credentialsMatcher = $passwordMatcher
[users]
[urls]
#.
#.
#.
/admin** = authc, roles[Admin]
/activity.xhtml = authc
/item.xhtml = authc, roles[Branch]
/unauthorized.xhtml = authc
When a user role say 'Branch' tries to access a url that is meant for 'Admin', user is safely redirected to '/unauthorized.xhtml'
Things changed however, when I decided to move authentication to Active Directory; shiro.ini looks like this:
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.userRolesQuery = select rolename from role where id in(select roleid from userrole where useraccountid = (select id from useraccount where username LIKE ?) and active = true) and active = true
jdbcRealm.dataSource = $ds
ADRealm = org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm
ADRealm.url = ldap://xxx.xxx.xxx.xxx:389
ADRealm.searchBase = "OU=Company Name,DC=domain,DC=local"
ADRealm.systemUsername= myuser
ADRealm.systemPassword= mypass
ADRealm.principalSuffix= #domain.local
securityManager.realms = $jdbcRealm,$ADRealm
Authentication happens okay, but trying to access the 'unauthorized url', breaks with the error:
[org.apache.shiro.authz.AuthorizationException: LDAP naming error while attempting to retrieve authorization for user [myusername]
How can I make authorization safely redirect to unauthorized url as before, without it breaking? I've even tried this:
authz = org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
authz.unauthorizedUrl = /unauthorized.xhtml
But without success.
Edit
Inshort, how can we configure shiro.ini to return http response 401/3 - (Unauthorized/forbidden) for necessary cases?
It looks like your /unauthorized.xhtml = authc config would block this if you are trying to reuse your 403 page for 401s.
You could probably use: /unauthorized.xhtml = anon (assuming this page didn't need your user context)
I am developing a jsf-based project using Apache Shiro 1.2 for security. I have a problem with 'remember me' feature.
[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery = SELECT password from user where username = ?
jdbcRealm.userRolesQuery = select role from userroles where userID = (select id FROM user WHERE username = ?)
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = 12345
ds.databaseName = testdb
jdbcRealm.dataSource= $ds
authc.loginUrl = /index.xhtml
user.loginUrl = /index.xhtml
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordMatcher.passwordService = $passwordService
jdbcRealm.credentialsMatcher = $passwordMatcher
#or this configuration
#passwordMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
#credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
#credentialsMatcher.hashAlgorithmName = SHA-256
#credentialsMatcher.storedCredentialsHexEncoded = true
#credentialsMatcher.hashIterations = 5000
Java class
PasswordService passwordService = new DefaultPasswordService();
String encryptedPassword = passwordService.encryptPassword(password);
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, encryptedPassword);
token.setRememberMe(rememberMe);
What could be the problem be?
You will need to configure a default session manager to hold the session that you are remembering.
[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
When i use grails spring security facebook plugin with MongoDB database, it keep throwing OptimisticLockingException on these section.
Then i override it with FacebookAuthService like these.
class FacebookAuthService {
def create(FacebookAuthToken token) {
FacebookUser fbUser = new FacebookUser(uid: token.uid)
fbUser.accessToken = token.accessToken?.accessToken
fbUser.accessTokenExpires = token.accessToken?.expireAt
Facebook facebook = new FacebookTemplate(token.accessToken.accessToken)
FacebookProfile fbProfile = facebook.userOperations().userProfile
User user = User.findByUsernameOrFacebookId(fbProfile.email,fbProfile.id)
if(!user){
user = new User()
user.facebookId = fbProfile.id
user.firstname = fbProfile.firstName.toLS()
user.lastname = fbProfile.lastName.toLS()
user.gender = Gender.strToEnum(fbProfile.gender)
user.acceptTerms = true
user.acceptTermsDate = new Date()
user.accountExpired = false
user.passwordExpired = false
user.accountLocked = false
user.enabled = true
user.username = "facebook_$token.uid"
user.password = token.accessToken.accessToken
}else{
user.facebookId = fbProfile.id
}
user.save(flush: true, failOnError: true)
fbUser.user = user
Role role = Role.findByAuthority('ROLE_USER')
if (role && !user.authorities.contains(role)) {
UserRole.create(user, role)
}
fbUser.save(flush: true, failOnError: true)
return fbUser
}
def getAppUser(FacebookUser facebookUser){
return facebookUser?.user
}
Collection<GrantedAuthority> getRoles(User user){
return UserRole.findAllByUser(user)?.role?.collect{ role ->
new GrantedAuthorityImpl(role.authority)
}
}
}
But now it throws Connection wait timeout after 120000 ms. Stacktrace follows:
Message: Connection wait timeout after 120000 ms
I know there is bug with GPMONGODB driver. and fixed it like described on there.
Please help me to fix it
Grails version 2.2.4
mongodb version 2.2.4
gpmongo driver version 1.3.0GA
spring security facebook plugin version :0.14.5
also it includes thse additional plugins to collect user information.
'org.springframework.social:spring-social-core:1.0.3.RELEASE'
'org.springframework.social:spring-social-facebook:1.0.3.RELEASE'
Edit:
I found out the cause
com.the6hours.grails.springsecurity.facebook.FacebookAuthProvider class's authenticate method keeps calling on every request. So what could be the cause of this loop ?
I have configured my application to work with multiple databases. The magic works just fine. In my Bootstrap.php I have defined the folowing:
protected function _initDb()
{
$resource = $this->getPluginResource('multidb');
Zend_Registry::set("multidb", $resource);
}
and in my application.ini:
resources.multidb.db1.adapter = mysqli
resources.multidb.db1.host = localhost
resources.multidb.db1.username = user
resources.multidb.db1.password = pass
resources.multidb.db1.dbname = db
resources.multidb.db1.charset= "utf8"
resources.multidb.db1.default= true
resources.multidb.db1.profiler.enabled = true
resources.multidb.oracle.adapter = oracle
resources.multidb.oracle.username = user
resources.multidb.oracle.password = pass
resources.multidb.oracle.charset= "utf8"
resources.multidb.oracle.dbname = "(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(Host = host.example.com) (Port = 1529)) (CONNECT_DATA = (SID = DB)))"
resources.multidb.oracle.profiler.enabled = true
All of this works just fine. In my models, I usually do something like this in the init():
$multidb = Zend_Registry::get("multidb");
$this->oracle = $multidb->getDb('oracle');
But I recently wanted to move this part to the Bootstrap, or rather, Registry, like this:
protected function _initDb()
{
$resource = $this->getPluginResource('multidb');
Zend_Registry::set("multidb", $resource);
Zend_Registry::set("odb",$resource->getDb('oracle'));
}
And this is what happened:
Fatal error: Uncaught exception 'Zend_Application_Resource_Exception' with message 'A DB adapter was tried to retrieve, but was not configured' in C:\Zend\Apache2\htdocs\Zend\Application\Resource\Multidb.php on line 135
I know a temporary fix around this, but why is this happening, and what could be a more long term fix, so that I could set each adapter in registry, preferably in bootstrap?
Thanks!
I think you have to make sure the multidb resource is bootstrapped in other to be filled. You can do this with the following:
protected function _initDb() {
$this->bootstrap('multidb');
$resource = $this->getPluginResource('multidb');
Zend_Registry::set("multidb", $resource);
Zend_Registry::set("odb",$resource->getDb('oracle'));
}