Adonis JS - Hashing Password - password-hash

I have gone through
http://adonisjs.com/docs/3.1/database-hooks#_hooks_events
http://adonisjs.com/docs/3.1/encryption-and-hashing#_hashing_values
https://adonisjs.svbtle.com/basic-authentication-with-adonisjs#using-hash-provider_3
https://auth0.com/blog/creating-your-first-app-with-adonisj-and-adding-authentication/
and a few more.
This should be fairly simple, but I don't know why I am not being able to figure it out. I want to use the Authentication tool of Adonis while "signing in". For this I need to Hash passwords before saving. I am stuck here.
View
<h1>Sign up</h1>
{{ form.open({url: '/addNew', action: 'UserController.addNewUser'}) }}
{{ csrfField }}
<div class="field">
{{ form.label('username', 'Choose a username') }}
{{ form.text('username') }}
</div>
<div class="field">
{{ form.label('email', 'Enter email address') }}
{{ form.text('email') }}
</div>
<div class="field">
{{ form.label('password', 'Choose a strong password') }}
{{ form.password('password') }}
</div>
<div class="button">
{{ form.submit('Sign Up') }}
</div>
{{ form.close() }}
Controller: UserController
'use strict'
const Database = use('Database')
const User = use('App/Model/User')
const user = new User()
class UserController {
* index (request, response) {
const users = yield Database.select('*').from('users')
response.json(users)
}
* addNewUser (request, response){
user.name = request.input('username')
user.email = request.input('email')
user.password = request.input('password')
user.entry = "Lorem Ipsum";
//Insert into database
const userId = yield Database
.insert({name: user.name, email: user.email, password: user.password, entry: user.entry})
.into('users')
response.json(userId)
}
}
module.exports = UserController
Model: User
'use strict'
const Lucid = use('Lucid')
class User extends Lucid {
static boot () {
super.boot()
this.addHook('beforeCreate', 'User.encryptPassword')
}
}
module.exports = User
Hook: User
'use strict'
const Hash = use('Hash')
const User = exports = module.exports = {}
User.encryptPassword = function * (next) {
this.password = yield Hash.make(request.input('password'))
yield next
}
Thanks!

You should be using the Model itself to create the record. Why are using the Database provider for that?
No where in the documentation it says to new up a model and then make a call using database provider. So it should be
Controller
* addNewUser (request, response) {
const user = new User()
user.name = request.input('username')
user.email = request.input('email')
user.password = request.input('password')
user.entry = "Lorem Ipsum";
yield user.save()
response.json(user.id)
}
Also inside your hook, you do not have access to the request object. I believe you did not bother reading the docs.
Hook
'use strict'
const Hash = use('Hash')
const User = exports = module.exports = {}
User.encryptPassword = function * (next) {
this.password = yield Hash.make(this.password)
yield next
}
Check the docs for hooks here http://adonisjs.com/docs/3.1/database-hooks#_basic_example
Hook for Adonis v4 inside model
class User extends Model {
static boot () {
super.boot()
this.addHook('beforeCreate', async (userInstance) => {
userInstance.password = await Hash.make(userInstance.password)
})
}
}
Check the docs for hooks here https://adonisjs.com/docs/4.1/database-hooks#_defining_hooks

There's a way to do it without using a Hook or Model. Simply by hashing the password in the controller itself. But I want to do it using the Hook. Anyways, here's the code:
Controller: UserController -> addNewUser()
user.name = request.input('username')
user.email = request.input('email')
const pswd = request.input('password')
user.password = yield Hash.make(pswd)
Note: I am not sure exactly which encryption Hash.make does. But the encryption tool of Adonis cannot verify the password. One more thing, the Hashed passwords always start with $2a$10$. Guys please help!

Related

How to add current user id to the axios.get request?

how can I add current user id to the axios.get request url in the front end code?
here are my codes;
backend: urls.py
urlpatterns = [
path('<int:pk>/', UserDetail.as_view()),
]
and views.py
class UserDetail(APIView):
permission_classes = [AllowAny]
http_method_names = ['get', 'head', 'post']
"""
Retrieve, update or delete a user instance.
"""
def get_object(self, pk):
try:
return NewUser.objects.get(pk=pk)
except NewUser.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
user = self.get_object(pk)
serializer = CustomUserSerializer(user)
return Response(serializer.data)
frontend:
useEffect(() => {
if (localStorage.getItem("access_token")) {
axiosInstance.get('users/**???**').then((obj) => {
{
setname(obj.username)
setemail(obj.email)
setidx(obj.uid)
}
console.log(obj);
console.log(obj.data);
setTimeout(() => {
props.resetProfileFlag();
}, 3000);
});
}
}, [props.success])
If I add user id manually (like say; axiosInstance.get('users/1').then((obj) => { ...) it gets the user details.
in your axios part you need to use params like these:
useEffect(() => {
if (localStorage.getItem("access_token")) {
axiosInstance.get('users/',
{
params: {
id: '1'
}
}).then((obj) => {
{
setname(obj.username)
setemail(obj.email)
setidx(obj.uid)
}
console.log(obj);
console.log(obj.data);
setTimeout(() => {
props.resetProfileFlag();
}, 3000);
});
}
}, [props.success])
and in the backend side you can get the data also from the request.params .
Thank you Rassaka, however, still I can't get a single user details, but I get the list of all users data at the console.
I moved to DRF Viewsets and HyperlinkedModelSerializers:
class UserSerializer(serializers.HyperlinkedModelSerializer):
posts = serializers.HyperlinkedRelatedField(
many=True,
queryset=Post.objects.all(),
view_name='blog:post-detail',
)
url = serializers.HyperlinkedIdentityField(view_name='users:user-detail')
class Meta:
model = User
fields = ('url', 'id', 'user_name', 'email', 'posts')
views.py :
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides `list` and `detail` actions.
"""
permission_classes = [AllowAny]
queryset = User.objects.all()
serializer_class = UserSerializer
#lookup_field = 'pk'
def post(self, request):
try:
refresh_token = request.data["refresh_token"]
token = RefreshToken(refresh_token)
token.blacklist()
return Response(status=status.HTTP_205_RESET_CONTENT)
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
urls.py:
urlpatterns = [
router.register(r'users/<int:pk>', views.UserViewSet),
router.register(r'users', views.UserViewSet),
]
urlpatterns = [ re_path(r'^', include(router.urls)) ]
and finally my react frontend:
const UserProfile = props => {
const [data, setData] = useState({
users: [],
});
useEffect(() => {
if (localStorage.getItem("access_token")) {
axiosInstance.get('users/', {params: { id: '1'}}).then((res) => {
setData({
users: res.data,
})
console.log(res.data);
setTimeout(() => {
props.resetProfileFlag();
}, 3000);
})
.catch(err =>{
console.log(err)
})
}
}, [setData], [props.success])
return (
<React.Fragment>
<div className="page-content">
<Container fluid>
<Row>
<Col lg="12">
<Card>
<CardBody>
<div className="d-flex">
<div className="ms-3">
<img
src={data.users.avatar}
alt=""
className="avatar-md rounded-circle img-thumbnail"
/>
</div>
<div className="align-self-center flex-1">
<div className="text-muted">
<h5>Username: {data.users.user_name} {''}</h5>
<p className="mb-1">Email: {data.users.email} {''}</p>
<p className="mb-0">Id no: {data.users.id} {''}</p>
</div>
</div>
</div>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</div>
</React.Fragment>
)
}
export default UserProfile
The issue is; after login I get the right user data in the console, however, when I go to the user profile page, firstly I get this error message "GET http://127.0.0.1:8000/api/users/?id=1 401 (Unauthorized)" in the console and of course in the backend terminal. But immediate after that the backend refreshs the token ""POST /api/token/refresh/ HTTP/1.1" 200" -> "GET /api/users/?id=1 HTTP/1.1" 200". But I get all user Arrays(data) - (not the logged-in user data) in the console, however, the user profile page cannot retrieve any user data. So I can not understand if user data cannot be retrieved to the profile page because the axiosInstanse refreshes token after login or because my frontend design is wrong. Or something is wrong with the backend?? Please, your advices? ...

Mapbox auto fill complete address

I use mapbox tools for my autofill place address autocomplete on my project Symfony
I want to know how can i extract full complete address in autofill, i have 2 inputs one for search and one hidden for get full/complete address
<mapbox-address-autofill>
{{ form_widget( form.address, {
'attr': {
'class': 'form-control form-control-solid font-weight-bold',
'placeholder': 'Adresse de départ',
'required': 'required',
'autocomplete': 'address-line1'
}
} ) }}
{{ form_widget( form.address_value, {
'attr': {
'autocomplete': 'full-address'
}
}) }}
</mapbox-address-autofill>
I have this but with tag 'full-addresse' 'complete' 'place_name'
No one workn if you have any solution for get full address to persist this in php Symfony project
"full_address" is a property of the feature object that is returned from a retrieve event, but does not automatically map to any HTML form field autocomplete value. The only object properties that get mapped to HTML elements are the ones corresponding to WHATWG standards, i.e.:
'street-address'
'address-line1'
'address-line2'
'address-line3'
'address-level1'
'address-level2'
'address-level3'
'address-level4'
'country'
'country-name'
'postal-code'
I'm not familiar with PHP, but a way to do this in Javascript would be something like:
const autofill = document.querySelector('mapbox-address-autofill');
const targetInput = document.getElementById('myTargetInput');
autofill.addEventListener('retrieve', (event) => {
const featureCollection = event.detail;
const feature = featureCollection[0];
const fullAddress = feature.properties.full_address;
targetInput.value = fullAddress;
});

next-auth php hash legacy users

I am working on creating a next js application and have legacy user data I need to import from a word press site. The word press site had a signup with credential or a Facebook social login.
For the legacy data [credentials i.e email password] I wrote a script in [...nextauth.js] for logging in the user as follows.
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'email', placeholder: 'Email' },
password: {
label: 'Password',
type: 'password',
placeholder: 'Password',
},
},
async authorize(credentials, req) {
const len = 8;
const portable = true;
const phpversion = 9;
const hasher = new PasswordHash(portable, phpversion);
const encrypted_input = hasher.HashPassword(credentials.password);
await db.connect();
const user_raw = await LegacyUser.findOne({ email: credentials.email });
const user = JSON.parse(JSON.stringify(user_raw));
console.log(user.password);
await db.disconnect();
const valid = hasher.CheckPassword(credentials.password, user.password);
if (valid) {
console.log(user);
console.log('validPassword');
return user;
} else {
console.log('Passwords dont match');
return null;
}
},
})
Where db is the connection defined for all reads and writes to the mongo db and LegacyUser is the mongoose model defined. I test it out and so far so good.
Now I need to store the user session in the same db so I define database as the .env mongodb uri like bellow, including the mongodb adapter as in the documentation of next-auth:
adapter: MongoDBAdapter(clientPromise),
database: process.env.MONGODB_URI,
Now when I try to sign in again with the legacy password I don't get signed in and unfortunately I have no errors to show.
Only to point out that the console.log('validPassword'); of the CredentialsProvider does come through successfully.
I have been stuck on this issue for a few days, so any help is greatly appreciated.
Many thanks

Freezing when signup using passport / express / mongodb

I'm working my way through a tutorial regarding passport.js and authentication and I'm coming unstuck. I'm just testing the signup function at the moment and my app is freezing. Here's my server file:
var express = require('express'),
app = express(),
mongoose = require('mongoose'),
passport = require('passport'),
flash = require('connect-flash'),
morgan = require('morgan'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
session = require('express-session');
// configDB = require('./config/database.js');
mongoose.connect('mongodb://localhost/Auth_practice');
require('./config/passport')(passport); // pass passport for config
// set up express app
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (required for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs') // set up ejs for templating
// required for passport
app.use(session({secret: 'ilovethetoonandrafa'})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // for persistent login
sessions
app.use(flash());
// routes
require('./app/routes.js')(app, passport); // load our routes
and pass in passport
app.listen(process.env.PORT, process.env.IP, function(){
console.log("Server has started")
});
Here's my user model:
// load the things we need
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define schema for our user model
var userSchema = mongoose.Schema({
local :{
email : String,
password : String,
},
facebook :{
id : String,
token : String,
email : String,
name : String
},
twitter :{
id : String,
token : String,
displayName : String,
username : String
},
google :{
id : String,
token : String,
email : String,
name : String
}
});
// method =========================
// generate a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// check if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
My strategy setup:
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var User = require('../app/models/user');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
And my route for signup
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile', // redirect to the secure profile of the
user
failureRedirect: '/signup', // redirect to signup page if failure
failureFlash: true // allow flash messages
}));
Finally here's the signup form:
<!-- views/signup.ejs -->
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Signup</h1>
<!-- show any messages that come back with authentication -->
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/signup" method="post">
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-warning btn-lg">Signup</button>
</form>
<hr>
<p>Already have an account? Login</p>
<p>Or go home.</p>
</div>
</div>
</body>
Can anyone see what's causing the app to freeze?

Symfony2 custom user provider can't retrieve user

I followed this guide to implement my own custom user login. Unfortunately it says Bad credentials during login. This exception comes from line 72 of Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider. This exception gets thrown because it can't retrieve the user.
What I changed for my custom needs is that the users do not have a username. They will login with their email address. But I think that would be no problem to implement.
security.yml:
security:
encoders:
Acme\UserBundle\Entity\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
administrators:
entity: { class: AcmeUserBundle:User }
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login: ~
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
UserRepository:
class UserRepository extends EntityRepository implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$q = $this
->createQueryBuilder('u')
->where('u.email = :email')
->setParameter('email', $username)
->getQuery();
try {
// The Query::getSingleResult() method throws an exception
// if there is no record matching the criteria.
$user = $q->getSingleResult();
} catch (NoResultException $e) {
$message = sprintf(
'Unable to find an active admin AcmeUserBundle:User object identified by "%s".',
$username
);
throw new UsernameNotFoundException($message, 0, $e);
}
return $user;
}
public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(
sprintf(
'Instances of "%s" are not supported.',
$class
)
);
}
return $this->find($user->getId());
}
public function supportsClass($class)
{
return $this->getEntityName() === $class
|| is_subclass_of($class, $this->getEntityName());
}
}
login.twig.html:
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<form action="{{ path('login_check') }}" method="post">
<legend>Login</legend>
<label for="email">Email:</label>
<input type="email" id="email" name="_email" value="{{ email }}"
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<button type="submit">Login</button>
</form>
What have I done wrong here? In UserRepository it clearly queries the email as username, so why can't it find the user? I have the speculation that it has something to do with the csrf_token? How can I add it to the controller and twig file? Is this the problem at all oder is it anything else I did wrong?
By default Symfony security uses _username and _password parameters to authenticate user via form submit. You can see it in security configuration reference
form_login:
username_parameter: _username
password_parameter: _password
So you need to place _username field name insteadof _email.