My question is related to PassportJS - Using multiple passports within Express application topic.
So as long as I already have two separate passport instances, I realized that they both share the same cookie, created here:
application.use(session({ secret: 'my secret cookie', key: 'usid' }));
I can add one more cookie with different name using this:
app.use(connect.session({ secret: 'keyboard cat', key: 'rsid' }))
However, it is not clear to me how to instruct each passport to use its own cookie.
I figured out temporary solution for passport 0.4.0 via
passport._key = passport._sm._key = 'customPassportSessionKey'
You can solve it by making from the router and not from the app. I've solved the same issue by developing something like an AuthBuilder which receives certain parameters, each instance generates a new passport that way.
class AuthBuilderService {
constructor() {
this.passport = new Passport();
this.registerSerializers(); // Multiple serializers
this.registerStrategies(); // Multiple strategies
}
Then you can register multiple routers with the same passport and key (or just one) by calling the authbuilder.addRouter(...)
addRouter(router, loginFileName, failureUrl, successUrl) {
router.use('/login', express.static(`${__dirname}/../views/whatever`, {
index: loginFileName,
fallthrough: true,
}));
router.use(session({
secret: 'any secret',
key: (_isRouterA()) ? 'a' : 'b',
resave: true,
saveUninitialized: true
}));
router.use(this.passport.initialize());
router.use(this.passport.session());
this._configureRouter(router, failureUrl, successUrl); // There I'm handling login, logout and some middleware.
return this;
}
From the routers you want to protect:
routerUsers_1.get('something_1', method)
routerUsers_2.get('something_2', method2)
let authBuilder = new AuthBuilderService();
authBuilder.addRouter(routerUsers_1, 'login_users_vip.html', '/path/failure_vip/', '/path/success_vip');
authBuilder.addRouter(routerUsers_2, 'login_users.html', '/path/failure/', '/path/success');
routerAdmins.get('something', methodAdmin)
new AuthBuilderService().addRouter(routerAdmins, 'login_admins.html', '/path2/failure/', '/path2/success');
Then express app just use each router.
app.use('path-client-vip', routerUsers_1)
app.use('path-client', routerUsers_2)
app.use('path-admin', routerAdmin)
I'm working with 2 webapps (with different users, logins and content) in the same express app server, each webapp uses different instances of this AuthBuilderService for multiple routers using different passport, sessions, strategies and serializers between each AuthBuilderService instance.
Hope it will help somebody.
Related
I'm trying to do a password less signIn & signOut in flutter with amplify, but I don't see an option on the amplify_auth_cognito package (that aws provides in pub.dev) that allows or hints me how to do it, is it even possible to do it with this package or should I use some other package? if yes then which one and how to do it?
The user pool that I'm using is from an actual working web application which I imported following the aws flutter documentaion
Thank you in advance.
What I experimented with was the default methods provided by amplify_auth_cognito as shown below:
var signUpConfirmedd = await auth.signUp(
username: _email,
// tried not filling the password field but it doesn't work
password: '1234567890',
options: CognitoSignUpOptions(
userAttributes: {
CognitoUserAttributeKey.email: _email,
CognitoUserAttributeKey.name: 'nityy'
},
),
);
I'm trying to import existing users from another application into Google Cloud Identity Platform using passwords that were hashed using PHP's crypt function with an MD5 output.
This is an example of the hashed password being used in PHP:
$hashed_password = '$1$AT$JGYIRSP7xIYmg1XSoJmvB1';
$user_input = 'test123';
if (hash_equals($hashed_password, crypt($user_input, $hashed_password))) {
echo "Password verified!";
}
I've tried all sorts of combinations for importing the user and their password, but no combination seems to work. This is the NodeJS import script I'm using:
var admin = require('firebase-admin');
var app = admin.initializeApp({
credential: admin.credential.applicationDefault()
});
admin
.auth()
.importUsers(
[
{
uid: '31',
email: 'user31#test.test',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('$1$AT$JGYIRSP7xIYmg1XSoJmvB1'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('$1$AT$'),
},
],
{
hash: {
algorithm: 'MD5',
rounds: 0,
},
}
)
.then((results) => {
console.log(results);
results.errors.forEach((indexedError) => {
console.log(`Error importing user ${indexedError.index}`);
});
})
.catch((error) => {
console.log('Error importing users :', error);
});
As mentioned above, I've tried just about every combination of hash and passwordSalt I could think of. I've tried:
passing no passwordSalt
passing a passwordSalt of AT
passing a passwordSalt of AT$
passing a passwordSalt of $AT
passing a passwordSalt of $AT$
all of the above but with a hash algorithm of BCRYPT
I can see the user getting imported. If I change the hash to something like a regular MD5 hash, I'm able to authenticate as that user, so I know the import process is working correctly.
Does GCP Identity Platform simply not support these hashes? Am I passing the salt incorrectly or passing an incorrect number of rounds? Am I passing the wrong hash algorithm? I'm a little surprised, as I would've thought passwords hashed using PHP's crypt function would've been supported.
4 points:
1.- You are mentioning that you are trying to import existing users and their passwords from another application into Google Cloud Identity Platform. Also, you mentioned that you are using a NodeJS import script focused on MD5. Based on that, and using the same official GCP documentation that you quoted Migrating users from an existing app vs the NodeJS’s script you posted, it seems that you didn’t use the code sample that is posted in that documentation, exactly in the way it should be used, unless that you are the owner of the domain "#test.test":
getAuth()
.importUsers(
[
{
uid: 'some-uid',
email: 'user#example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt'),
},
],
{
hash: {
algorithm: 'PBKDF2_SHA256',
rounds: 100000,
},
}
)
.then((results) => {
results.errors.forEach((indexedError) => {
console.log(`Error importing user ${indexedError.index}`);
});
})
.catch((error) => {
console.log('Error importing users :', error);
});
2.- Are we sure you have the required admin rights or role over IAM in your GCP’s Organization? You can use the following official GCP documentation for understanding roles Understanding roles
3.- How are you figuring out that it is not working? Are you facing any of the following errors? Error codes. Is there any particular behavior after the importing process finishes or any log that you can share here editing your original post? Or is it only because you see that once the users are imported to IAM, they are not able to authenticate?
4.- I suggest you by now to follow (Method: users.insert) as stated here Method: users.insert first, this way you are going to review the hash formats that are supported. Finally, you need to do this test with the domains that you have verified in Cloud Identity.
I'm building a restricted signup. I want user with a specific code passed in a url to be able to signup and not others. I'm using the accounts package.
I can prevent account creation in the Accounts.onCreateUser method. I'm looking for a way to tell the server if the client had an authorised signup code. With a classic form (email+password) I can just add an extra hidden field. How can I achieve the same result if the user signs up with let's say Facebook?
Since Meteor doesn't use cookies, I can't store this info in a cookie that the server would access. Session variable are not accessible server side. And since I'm not controlling what got send with the account-facebook creation, I can't use a Session variable on the client side that I'd pass along when the user presses sign up.
Any idea"?
Just add the special token to the user object being passed to Accounts.createUser():
var user = {
email: email,
password: password,
profile: {
token: token
}
};
Accounts.createUser(user, function (error, result) {
if (error) {
console.log(error)
}
});
On the server side you can access this in the Accounts.onCreateUser():
Accounts.onCreateUser(function(options, user) {
console.log(options);
console.log(user);
});
I think it's in the options variable that you will find your token, so it would be options.profile.token.
for me, the best option here was passing in custom parameters to loginbuttons.
see the package docs:
https://github.com/ianmartorell/meteor-accounts-ui-bootstrap-3
Where it outlines the below:
accountsUIBootstrap3.setCustomSignupOptions = function() {
return {
mxpDistinctId: Session.get('mxpdid'),
leadSource: Session.get('leadSource')
}
};
I have an application using ember-couchdb-kit to interface with a CouchDB instance. I am having difficulty accessing the server after requiring authentication.
I tried cookie authentication and the cookie gets set in the browser, but it isn't sent to the database for subsequent requests according to the network dialog in both Chrome and Firefox.
I don't understand why this is happening, but in the pursuit of getting the application working, I wanted to try HTTP auth.
My document adapter is just:
App.Host = 'http://localhost:5984'
App.ApplicationAdapter = EmberCouchDBKit.DocumentAdapter.extend( { db: 'wells', host: App.Host } )
I want to add the username and password to the URL, so after the user enters them, I run:
EmberCouchDBKit.DocumentAdapter.reopen( {
host: ( function() {
var parts = App.Host.split( '://' )
return "%#://%#:%##%#".fmt( parts[0], $('#username').val(), $('#password').val(), parts[1] )
} )()
} )
The URL for subsequent requests doesn't change though. What do I need to do?
The adapter isn't recreated each time it's used, and reopen only applies to newly created instanes. As such you'll need to redefine it on the already existing adapter instance. Inside a route/controller you could do it like so:
var adapter = this.store.adapterFor('application');
adapter.set('host', 'foobar');
I have an Ember app with a login form which returns the current user in JSON format after successful login.
Using createRecord sets the returned JSON attributes directly on the model. For instance, is_private becomes user.is_private, not user.get('isPrivate')?
How do I load the user model so that the attributes are set correctly and I don't have to re-fetch it using the id?
As of a few days ago in ember data 1.0 beta you can use pushPayload to load data directly into the store. For example if you get data pushed to your app through WebSockets (we use the Heroku add-on Pusher). You can call it on the store (source) directly and it will pass it through the appropriate serializer:
var postsJSON = {
posts: [
{id: 1, post_title: "Great post"}
]
}
this.store.pushPayload('post',postsJSON)
NOTE that it will not currently load a singular object (ie post: {id: 1, post_title:"First!"}) - you need to format it as plural with an array.
DS.RESTSerializer has pushPayload as well (source), in which case you need to pass it the store instead.
I highly encourage reading the source code before using, as it looks like the implementation of it will be revisited.
Supposedly, the official way to do this is using adapter.load, as described in this thread:
Loading Data
Previously, some features of the store, such as load(), assumed a
single adapter.
If you want to load data from your backend without the application
asking for it (for example, through a WebSockets stream), use this
API:
store.adapterForType(App.Person).load(store, App.Person, payload);
This API will also handle sideloaded and embedded data. We plan to add
a more convenient version of this API in the future.
But unfortunately, it doesn't handle sideloaded data, despite what the documentation claims. I personally use something like the following, which is based on how find(ID) is implemented:
var id = json["person"]["id"];
var store = DS.get("defaultStore");
var adapter = store.adapterForType(App.Person);
adapter.didFindRecord(store, App.Person, json, id);
var person = App.Person.find(id);
Note that this code assumes JSON in the same format that find(ID) expects to receive from the server, as documented in the RESTAdapter guide:
{
person: {
id: 1,
is_private: false,
projects: [3]
},
projects: [
{ id: 3, name: "FooReader" }
]
}
This will apply any transformations you've configured using keyForAttributeName (such as mapping is_private to isPrivate), and it will handle sideloaded records. I'm not sure if this is a best practice, but it works quite well.
how about store.push('user', userJSON)?
http://emberjs.com/guides/models/pushing-records-into-the-store/#toc_pushing-records
All answers above did not work for me.
What only worked for me was:
this.store.buildRecord(this.store.modelFor('person'), data.id, data)