In the simple case outlined below, the user will successfully import but I receive an INVALID_PASSWORD when I try to authenticate.
The salt and passwordHash where pulled from an LDAP user directory (apacheds) using the {SSHA} auth schema. When I run the following JS I receive the passwordHash I'm expecting:
var sha1Hex = require('sha1-hex');
var saltHex = Buffer.from("ktuF+dzYMQU=", 'base64').toString('hex');
var passwordHex = Buffer.from("demo", 'utf-8').toString('hex');
var hash = sha1Hex(Buffer.from(passwordHex + saltHex, 'hex'));
var hashBase64 = Buffer.from(hash, 'hex').toString('base64');
console.log(hashBase64);
firebase CLM import command:
firebase auth:import users.json --hash-algo=SHA1 --rounds=80
users.json file:
{
"users": [
{
"localId": "3c872eee-e86c-4b44-9840-bcebaac18f2c",
"email": "test#example.com",
"salt": "ktuF+dzYMQU=",
"passwordHash": "BuapoGGKIdfGprfMFjj3N9I7Ljg=",
"displayName": "Demo User",
}
]
}
Credentials that should work with imported user:
Username: test#example.com
Password: demo
Firebase web api login command (returns INVALID_PASSWORD):
firebase.auth().signInWithEmailAndPassword('test#example.com', demo);
I'm not confident about the --rounds=80 parameter, seems weird that needs to be specified at all when using sha1. I've also tried with --rounds=0.
After trying this out with Java MessageDigest SHA-1 to verify the password hash, one of our uber auth experts said that it looks like you're doing passwordHash = SHA1(plainPassword + salt)
However, the Firebase Auth system uses passwordHash = SHA1(salt + plainPassword).
So I think if you switch that around, it should produce better results.
You can configure the order of the password and hash.
The hash-input-order accept two values: SALT_FIRST or PASSWORD_FIRST.
In your case you want to do:
firebase auth:import users.json --hash-algo=SHA1 --rounds=80 --hash-input-order=PASSWORD_FIRST
For anyone like me that went hours finding a solution for this issue, please refer to this.
Basically, passwordHash should be in Base64 encoding from un-hex-ed SHA1 hash. And --rounds=1 works fine.
Related
I’m working on a react native application that uses [Firebase Email Link (passwordless) Auth]((https://firebase.google.com/docs/auth/web/email-link-auth)
I have created a ‘users’ collection on the Firestore database.
In order to easily sync users profile data to the redux store,I decided to use react-redux-firebase
I have already configured the rrfConfig and followed every single steps as stated in the getting started documentation, but still remain some parts that unclear and not documented. It’ll be great to get someone’s help on any ideas on how to tackle this part:
1) How to log in users with firebase.login({params}) that are signed up with email link (passwordless) using the methods outlined in the auth section?
This the email/password example:
firebase.login({
email: 'test#test.com',
password: 'testest1'
})
Since the user does not have a password, or credential or accessToken after he signed up using email link firebase.auth().signInWithEmailLink(email, window.location.href) all we have is a uid and email:
firebase.login({
email: 'test#test.com',
// any ideas to add here?
})
2) Similarly, how to create users with createUser(credentials, profile) using [email link (passwordless)](https://firebase.google.com/docs/auth/web/email-link-auth
) auth?
const createNewUser = ({ email, password, username }) => {
firebase.createUser( // should password be replaced by url?
{ email, password },
{ username, email }
)
}
Thank you in advance for helping out with any ideas on how to tackle this
I want to add multiple users with pre define paswword to Firebase Authentication project
I know it can be done using Hash password but in my case i have the real password not the generated hash password
can i user firebase auth:import to upload using realpassword or are there any way to convert real password to hash password using my project hash parameters ??
for example
You can hash with SHA256 and import these users. Here is an example in Node.js using the Admin SDK:
import * as crypto from 'crypto';
const importOptions = {
hash: {
algorithm: 'SHA256',
rounds: 1,
},
};
// For every user, you generate the password hash and a salt.
const currentRawSalt = generateRandomSalt();
const computedPasswordHash = crypto.createHash('sha256').update(currentRawSalt + yourUserPlainPassword).digest();
importUserRecord = {
uid: yourUserUid,
email: youUserEmail,
passwordSalt: Buffer.from(currentRawSalt),
passwordHash: computedPasswordHash,
};
admin.auth().importUsers([importUserRecord], importOptions)
.then((result) => {
// Check result to confirm success.
});
There's no way to import with a plain text password. You will have to generate the password hash to import them. There are a lot of hashing options, all described in the documentation on importing users with the Admin SDK.
I did the below work around
I stored all users data in excel sheet
Then I loop in sheet data and called sign up method for each row
I am having difficulty using the FirebaseApp (a 3rd party API) to generate an authentication token that can be passed to a sidebar and used by the client to login and access my Firebase Database client-side.
I'm trying to use this tutorial but cannot get it working without using a database secret (which is being depreciated) in makeToken(). I'd prefer to use a service account as reflected in this tutorial. When I look at the difference between the tokens generated, the first 2 pieces separated by a '.' are identical, the last piece after the final '.' is different. The lengths are the same as well. eg:
//Example Generated by Database Secret: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2U=
//Example Generated by Service Account: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbml=
I can generate the OAuth access token, pass it to FirebaseApp and generate an authentication token, but when it is passed client-side and I attempt to authenticate I get an error: Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.
It seems like there is a lot of misinformation and conflicting information on how this should be done.
I have a getFirebaseService() function server-side that uses Apps Script OAuth2 Library to get an access token.
function getFirebaseService() {
return OAuth2.createService('Firebase')
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(fb_PRIVATE_KEY) //Service account private key
.setIssuer(fb_SERVICE_EMAIL) //Service account email
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scopes.
.setScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database');
}
I have a makeToken() function server-side that gets an authentication token from Firebase using the OAuth access token. I am able to use the service.getAccessToken() OAuth token server-side to access and store data. So that works, I guess my issue is creating a client auth token that's more restrictive.
function makeToken(){
var service = getFirebaseService();
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //Database Secret Works: "AAslhfi3MYACCESSTOKEN2930hf03ah4th8" but is being depreciated.
.createAuthToken(Session.getActiveUser().getEmail());
} else {
Logger.log("makeToken: " + service.getLastError());
}
}
Then client-side, from the sidebar, I try to authenticate with a custom auth token retrieved server-side from makeToken().
var userAuthToken;
google.script.run.withSuccessHandler(function (requestAuthToken) {
userAuthToken = authenticateClient(requestAuthToken)
}).makeToken();
function authenticateClient(userRequestToken) {
var ref = new Firebase(fb_URL);
ref.authWithCustomToken(userRequestToken, function (error, authData) {
if (error) {
console.log("FB Login Failed!", error); //Error below come from here.
}
else {
console.log("FB Login Succeeded!", authData);
}
});
return ref.authData.auth;
}
This results in Login Failed! Error: INVALID_TOKEN: Failed to validate MAC..
Edit: Is it possible FirebaseApp is incorrectly generating the JWT Authentication Token?
Edit2: I think the above edit is unlikely as I attempted to use the GSApp library and had the same issue. It only seems to want the depreciated database secret, not a service account OAuth.
Alright, so after a very long day I figured it out. I'm going to lay out what I ended up using for libraries and what the issue was (see the third library). The main problem was essentially that the tutorial was outdated and no a lot of people use Firebase in apps script.
OAuth2 (Server-side)
Link
I didn't have to change anything here! It was working fine and never an issue.
FirebaseApp (Server-side)
Link
This is a nice library and I stuck with it because it worked well (once I got it there). I had to make a change to my original code that came from the tutorial I mentioned. My code ended up like this and worked:
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //get OAuth Token
.createAuthToken(Session.getEffectiveUser().getEmail(), null, serviceAccount.client_email, serviceAccount.private_key);
//... Added the null, private key, and service email parameters.
Firebase (Client-side)
Link
Alright, so this is where my main issue was -- The tutorial I followed for client-side setup was old. I had to upgrade the code on my own to use the new 3.x version:
<script src="https://www.gstatic.com/firebasejs/5.8.2/firebase.js"></script>
// Initialize Firebase
var config = {
apiKey: "<Web API Key>",
authDomain: "<Project ID>.firebaseapp.com",
databaseURL: "https://<DB URL>.firebaseio.com/"
};
firebase.initializeApp(config);
With this firebase instance I was able to update my original authenticateClient() method:
function authenticateClient(userRequestToken) {
firebase.auth().signInWithCustomToken(userRequestToken).catch(function(error) {
// Handle Errors here.
console.error("authClient: ", error.code, error.message);
});
return {
uid: firebase.auth().currentUser.uid,
metadata: {
lastSignInTime: firebase.auth().currentUser.lastSignInTime
}
};
}
That's it! I now have a firebase instance with a signed in user via JWT Custom Token! I came across a few people with similar issues an I hope this helps.
I have been playing around with firebase tutorials and the new functions, and trying to implement this specific example:
https://github.com/firebase/functions-samples/tree/master/quickstarts/email-users
When I fire the trigger the mail does not get sent, and I get the following error in the log console:
Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8 https://support.google.com/mail/?p=BadCredentials 141sm3120746ioe.47 - gsmtp
at SMTPConnection._formatError (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:557:19)
at SMTPConnection._actionAUTHComplete (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:1248:34)
at SMTPConnection._responseActions.push.str (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:340:26)
at SMTPConnection._processResponse (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:706:20)
at SMTPConnection._onData (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:509:14)
at TLSSocket._socket.on.chunk (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:461:47)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:176:18)
at TLSSocket.Readable.push (_stream_readable.js:134:10)
What am I doing wrong? It does not say anthing about placing some authorizations on email account. Just the password. Should be simple.
If you type: firebase functions:config:get in the Terminal, you would be able to see that the gmail and password is with double quotation marks.
Mine was like this:
{
"gmail": {
"password": ""pass"",
"email": ""user#gmail.com""
}
}
So I typed in like this in the Terminal and it worked for me:
WITHOUT QUATATION MARKS
firebase functions:config:set gmail.email=user#gmail.com gmail.password=pass
not too sure if you've done the initial configuration part as listed here
For Gmail, enable these:
1. https://www.google.com/settings/security/lesssecureapps
2. https://accounts.google.com/DisplayUnlockCaptcha
If you have already done this, you can pass the email and password as a string on const gmailEmail = 'gmail.com' and const gmailPassword = 'password' to check if it's working
I'm using HTTP.post in meteor and I need to send basic authentication with only a username to an external service. Where does this go and what would that look like?
I am only using it on the server side so I know it should look like the below code, but I'm not sure where to put the username and what to call it.
I've tried this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"},
authentication: {"MYKEYHERE":""}
});
And this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"authentication": "MYKEYHERE",
"processor_uri": "/customers/customerURI"}
});
And this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"
},
headers: {'Authorization': 'MYKEYHERE'}
});
I get this error each time.
Error: failed [403] 403 Forbidden Access was denied to this resource.
Unauthorized: CustomerIndexView failed permission check
The plain auth : 'username:password' should do (from docs):
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"},
auth: 'yourkey:'
});
As per the balanced payments documentation:
To authenticate with Balanced, you will need the API key secret provided from the dashboard. You have to use http basic access authentication. Your key has to be set as the username. A password is not required for simplicity.
So this means you leave the password blank, so its just your key followed by the colon :
Also you might want to consider using the balanced package for Meteor which does all the boilerplate for you.