Using JDBCRealm to authenticate user with Shiro - shiro

I am trying to authenticate a servlet running within Tomcat 6 using Shiro.
I have the following shiro.ini file:
[main]
ps = org.apache.shiro.authc.credential.DefaultPasswordService
pm = org.apache.shiro.authc.credential.PasswordMatcher
pm.passwordService = $ps
aa = org.apache.shiro.authc.credential.AllowAllCredentialsMatcher
sm = org.apache.shiro.authc.credential.SimpleCredentialsMatcher
jof = org.apache.shiro.jndi.JndiObjectFactory
jof.resourceName = jdbc/UserDB
jof.requiredType = javax.sql.DataSource
jof.resourceRef = true
realm = org.apache.shiro.realm.jdbc.JdbcRealm
realm.permissionsLookupEnabled = true
realm.credentialsMatcher = $pm
; Note factories are automatically invoked via getInstance(),
; see org.apache.shiro.authc.config.ReflectionBuilder::resolveReference
realm.dataSource = $jof
securityManager.realms = $realm
[urls]
/rest/** = authcBasic
/prot/** = authcBasic
And the following in my database:
mysql> select * from users;
+----------+------------------+----------+----------------------------------------------+--------------------------+
| username | email | verified | password | password_salt |
+----------+------------------+----------+----------------------------------------------+--------------------------+
| admin | a.muys#********* | 1 | ojSiTecNwRF0MunGRvz3DRSgP7sMF9EAR77Ol/2IAY8= | eHp9XedrIUa5sECfOb+KOA== |
+----------+------------------+----------+----------------------------------------------+--------------------------+
1 row in set (0.00 sec)
If I use the SimpleCredentialsManager it authenticates fine against a plaintext password in the users table. Trying to use the PasswordMatcher has been extremely frustrating.
The password and password_salt were obtained via the shiro-tools Hasher utility.
When I try to authenticate against a basic HelloWorld servlet I use for testing (path=rest/hello, context=/ws), I get the following in the logs:
15:35:38.667 [http-8080-2] TRACE org.apache.shiro.util.ClassUtils - Unable to load clazz named [ojSiTecNwRF0MunGRvz3DRSgP7sMF9EAR77Ol/2IAY8=] from class loader [WebappClassLoader
context: /ws
delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader#79ddd026
]
(Full log at https://gist.github.com/recurse/5915693 )
It appears to be trying to load my hashed password as a classname. Is this a bug, or a configuration error on my part? If it is a bug, how can I work around it? If it is a configuration error, what am I missing?

First, thanks for providing a lot of information for this question - it makes providing an answer a lot easier.
By looking at your sample database row list, it does not appear that you are storing the output that the PasswordService expects when performing a hashed password comparison. For example:
$ java -jar ~/.m2/repository/org/apache/shiro/tools/shiro-tools-hasher/1.2.2/shiro-tools-hasher-1.2.2-cli.jar -p
Password to hash:
Password to hash (confirm):
$shiro1$SHA-256$500000$uxaA2ngfdxdXpvSWzpuFdg==$hOJZc+3+bFYYRgVn5wkbQL+m/FseeqDtoM5mOiwAR3E=
The String that starts with $shiro1$ is what you would save to the password column in the database. There is no need for a separate salt column as all the information Shiro needs is in the $shiro1$... String.
The DefaultPasswordService uses the same default configuration parameters (SHA-256, 500,000 iterations, etc) so if you use the Hasher CLI tool as I've shown above (no extra hash algorithm config), you don't need to customize the DefaultPasswordService POJO any further. However, if you change the hashing parameters on the CLI, you need to ensure that the same parameters are configured on the DefaultPasswordService bean (and/or its internal HashingService).
If you are still in testing and can change your DB schema, I'd recommend doing that now to have a single password field that stores the $shiro1$... string. Then you use the PasswordService as documented here under Usage:
http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/credential/PasswordService.html

Related

Where exactly do we place this postgresql.conf configuration file in spring boot application?

I am trying to encrypt a column in my prostrgres DB. The column name is "test" of type "bytea".
My enity code is below,
#ColumnTransformer(read = "pgp_sym_decrypt(" + " test, "
+ " current_setting('encrypt.key')"
+ ")", write = "pgp_sym_encrypt( " + " ?, "
+ " current_setting('encrypt.key')" + ") ")
#Column(columnDefinition = "bytea")
private String test;
postgresql.conf configuration file:
encrypt.key = 'Wow! So much security.
Placed the postgresql.conf configuration file in src/main/resources of spring boot appln. But the encryption.key value is not being picked up. And is there a way to pass the key using application.properties?
postgresql.conf is the configuration file for the Postgres server. It's stored inside the data directory (aka "cluster") on the server.
You can't put it on the client side (where your application runs). It has no meaning there.
To change values in there, you need to edit the file (on the server) or use ALTER SYSTEM.
If you want to change a configuration setting for the current session, use SET or set_config()
The latter two are probably the ones you are looking for to initialize the custom property for your encryption/decryption functions.
The way to use encrypt.key, not only for current session, it's store it in postgresql.conf.
The correct place is at the end of this file, in the "Customized Options" section:
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here
encrypt.key=123456
Reload the configuration of the database server:
systemctl reload postgresql.service
To testing if it's working correctly. Open a pgsql session and type:
mydb=# show encrypt.key;
encrypt.key
-------------
123456
(1 row)
Example of encrypt:
mydb=# select pgp_sym_encrypt('Hola mundo',current_setting('encrypt.key'));
pgp_sym_encrypt
------------------------------------------------------------------------------------------------------------------------------------------------------------
\xc30d04070302255230e388dfe25e7dd23b01c5b8e62d148088a3417d3c27ed2cc11655d863b271672b9f076fffb82f1a7f074f2ecbe973df04642cd7a4f76ca5cff4a13b9a71e7cc6e693827
(1 row)
Example of decrypt:
mydb=# select pgp_sym_decrypt('\xc30d04070302255230e388dfe25e7dd23b01c5b8e62d148088a3417d3c27ed2cc11655d863b271672b9f076fffb82f1a7f074f2ecbe973df04642cd7a4f76ca5cff4a13b9a71e7cc6e693827',current_setting('encrypt.key'));
pgp_sym_decrypt
-----------------
Hola mundo
(1 row)

Database table has different schema than model description in Flask application

I have an old application that I'm redeploying. The following model class:
class TableA(db.Model):
id = db.Column(db.Integer, primary_key=True)
name_key = db.Column(db.String(20), index=True, unique=True, nullable=False)
acronym_key = db.Column(db.String(6), index=True, unique=True, nullable=False)
has the following table in postgres:
Table "public.tablea"
Column | Type | Collation | Nullable | Default
-------------+------------------------+-----------+----------+----------------------------------
id | integer | | not null | nextval('tablea_id_seq'::regclass)
name_key | character varying(10) | | not null |
acronym_key | character varying(6) | | not null |
Notice the length of the column name_key, it does not match.
As I worked in this when I still didn't know what I was doing with the migrations, I double checked if I had left changes that were not saved as migrations, with
flask db migrate and flask db upgrade. I got some changes to the db, but not this one. Do column lengths do not generate migration changes? What am I missing? Any help is appreciated.
Adding to #PeterBlahos' link, alembic needs to be configured to notice differences in column lengths.
For that you need to modify {project-root}/migrations/env.py, modify the run_migrations_* methods context.configure segments by adding the compare_type=True as in the snippet bellow:
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True, compare_type=True)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True
)
with context.begin_transaction():
context.run_migrations()
After that just run on your terminal flask db migrate -m "some explanation for the changes" to create the migration file and flask db upgrade for the changes to actually affect the db.
Big thanks to #PeterBlahos who actually answered 85% of the question :).

Data Driven testing with cucumber protractor

Lets say I have a scenario in my demo.feature file
Scenario Outline: Gather and load all submenus
Given I will login using <username> and <password>
When I will click all links
Examples :
| username | password |
| user1 | pass1 |
| use2 | pass2 |
lets say i have a file called users.json
How can i get those usernames and passwords from that external file to my demo.feature ?
Can I catch the file by passing parameters to my npm script like below ?
npm run cucumber -- --params.environment.file=usernames.json
I recommend having the login step access that json file within the step definition. Just make sure not to check it into the repo and instead always expect it to be in a location but only locally and not in the repository.
Doing the above is useful for a couple of reasons:
- An engineer running your tests does not need to know that a param must be passed in from the command line
- The code is self-descriptive in that step as to how it logs in
- You can add better error handling
- You can use multiple user files if needs be by having hooks define paths etc based on tags

Issues with scheduling... Using tasksheduleR to run R script using rtweet and exporting to postgreSQL table

I am trying to schedule an R script to run, using rtweet to hit the Twitter API and then using RPOSTgreSQL to load the data into a table once a day.
I was able to successfully use taskscheduleR to create the task. However, when it runs I get an error that says...
<credentials> oauth_token, oauth_token_secret
---
Requesting token on behalf of user...
Error: API user token required. see http://rtweet.info/articles/auth.html for instructions
Execution halted
Here is my entire code with a few things masked due to API credentials and database info, passwords, etc
#load all packages
library(rtweet)
library(sqldf)
library(dplyr)
library("RPostgreSQL")
#connect to Twitter API
create_token(
app = "masked for stack",
consumer_key = "masked for stack",
consumer_secret = "masked for stack",
access_token = "masked for stack",
access_secret = "masked for stack")
## get user IDs of accounts following
followers=get_followers("masked for stack", n = 1000)
## lookup data on those accounts
followers_data=lookup_users(followers$user_id)
#add the date of the run
followers_data$date=Sys.Date()
#extract columns
twitter_followers=dplyr::select(followers_data,"date","screen_name","name","location","description","followers_count",
"friends_count","listed_count","statuses_count","favourites_count","verified")
# create a connection
# save the password that we can "hide" it as best as we can by collapsing it
pw <- {
"masked for stack"
}
# loads the PostgreSQL driver
drv <- dbDriver("PostgreSQL")
# creates a connection to the postgres database
# note that "con" will be used later in each connection to the database
con <- dbConnect(drv, dbname = "masked for stack",
host = "localhost", port = 5432,
user = "postgres", password = pw)
rm(pw) # removes the password
# writes df to the PostgreSQL database
dbWriteTable(con, "twitter_followers",
value = twitter_followers, append = TRUE, row.names = FALSE)
My code runs perfectly fine doing everything on my own manually. It seems that rtweet doesn't like getting ran by windows scheduler.
Any ideas? `
So after hours of digging I figured out that something was not working well with the scheduleR app. It may have been creating a task in windows scheduler that wouldn't run when my laptop was on AC power I'm not sure. Either way I did a workaround like this.
Created a text file and saved as a .bat extension with the following format:
"C:\Program Files\R\R-3.5.2\bin\x64\R.exe" CMD BATCH file_location.R
From there I scheduled in Windows scheduler. Make sure you go through all the options and don't choose a basic task. If you do a basic one you may not allow it to run on laptop battery power.

why wildfly server is asking me to add users even after adding user?

mngmt-users.properties file. The users are added in the file but when I try to run the localhost it says it's running then if I try to view the admin console it is redirecting to http://localhost:9990/error/index_win.html. That tells the server is running but I could not open admin console.
#
# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
# for new installations. Further authentication mechanism can be configured
# as part of the <management /> in standalone.xml.
#
# Users can be added to this properties file at any time, updates after the server has started
# will be automatically detected.
#
# By default the properties realm expects the entries to be in the format: -
# username=HEX( MD5( username ':' realm ':' password))
#
# A utility script is provided which can be executed from the bin folder to add the users: -
# - Linux
# bin/add-user.sh
#
# - Windows
# bin\add-user.bat
#
#$REALM_NAME=ManagementRealm$ This line is used by the add-user utility to identify the realm name already used in this file.
#
# On start-up the server will also automatically add a user $local - this user is specifically
# for local tools running against this AS installation.
#
# The following illustrates how an admin user could be defined, this
# is for illustration only and does not correspond to a usable password.
#
#admin=2a0923285184943425d1f53ddd58ec7a
tejaswini=25ab658c2861b2e64783aaa9ba95c2e5
aswini#19=388ced81791ddb1760b83dc4ec8b7a61
saisana=ff39d778414ab12d84fc4fa7fdacb634
alekya=d72e9c90345ce4d9290c3a2728b3cd60
prasad=c6c7c67cf343f6862d3b77bae9f61d17
teju=28b9e55b314fd60855a7843b4455dbed
Screen shot of added user
May be u have tried to create specifically application user or management user when u ran the addUser utility,
please refer the below link for steps to register user
https://bgasparotto.com/add-user-wildfly