Browse Source

Refactoring

Move basic authentication out into separate function
Add error handling
issue-90
8legd 8 years ago
parent
commit
4ea6f44a80
  1. 122
      username-password-auth/functions/index.js

122
username-password-auth/functions/index.js

@ -38,81 +38,105 @@ const basicAuthRequest = require('request');
* Authenticate the provided credentials returning a Firebase custom auth token.
* `username` and `password` values are expected in the body of the request.
* If authentication fails return a 401 response.
* If the request is badly formed return a 400 response.
* If the request method is unsupported (not POST) return a 403 response.
* If an error occurs log the details and return a 500 response.
*/
exports.auth = functions.https.onRequest((req, res) => {
const handleError = (username, error) => {
console.error({
User: username
}, error);
return res.sendStatus(500);
}
const handleResponse = (username, status, body) => {
console.log({
User: username
}, {
Response: {
Status: status,
Body: body
}
});
if (body) {
return res.status(200).json(body);
}
return res.sendStatus(status);
}
let username = '';
try {
cors(req, res, () => {
// Authentication requests are POSTed, other requests are forbidden
if (req.method !== 'POST') {
return res.sendStatus(403);
return handleResponse(username, 403);
}
let username = req.body.username;
username = req.body.username;
if (!username) {
return res.sendStatus(400);
return handleResponse(username, 400);
}
let password = req.body.password;
const password = req.body.password;
if (!password) {
return res.sendStatus(400);
return handleResponse(username, 400);
}
let creds = {
'auth': {
'user': username,
'pass': password
// TODO(DEVELOPER): In production you'll need to update the `authenticate` function so that it authenticates with your own credentials system.
authenticate(username, password).then(valid => {
if (!valid) {
return handleResponse(username, 401); // Invalid username/password
}
}
// For the purpose of this example use httpbin (https://httpbin.org) for the basic authentication request.
// (Only a password of `Testing123` will succeed)
const authEndpoint = `https://httpbin.org/basic-auth/${username}/Testing123`;
basicAuthRequest(authEndpoint, creds, (error, response, body) => {
let statusCode = response ? response.statusCode : 0;
if (statusCode === 401) { // Invalid username/password
return res.sendStatus(401);
}
if (statusCode !== 200) {
console.log('ERROR: invalid response returned from ', authEndpoint, ' status code ', statusCode);
return res.sendStatus(500);
}
// On success create/update the Firebase account and return the Custom Auth Token.
// - any extra user details can also be created/updated here
createFirebaseAccount(username).then(firebaseToken => {
return res.status(200).json({
// On success return the Firebase Custom Auth Token.
admin.auth().createCustomToken(username).then(firebaseToken => {
return handleResponse(username, 200, {
token: firebaseToken
});
}).catch(error => {
return handleError(username, error);
});
}).catch(error => {
return handleError(username, error);
});
});
} catch ( error ) {
console.log('ERROR:', error);
return res.sendStatus(500);
return handleError(username, error);
}
});
/**
* Creates a Firebase account with the given user id and returns a custom auth token allowing
* signing-in this account.
*
* @returns {Promise<string>} The Firebase custom auth token in a promise.
* Authenticate the provided credentials.
* TODO(DEVELOPER): In production you'll need to update this function so that it authenticates with your own credentials system.
* @returns {Promise<boolean>} success or failure.
*/
function createFirebaseAccount(uid) {
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, {}).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
return admin.auth().createUser({
uid: uid
});
function authenticate(username, password) {
// For the purpose of this example use httpbin (https://httpbin.org) and send a basic authentication request.
// (Only a password of `Testing123` will succeed)
const authEndpoint = `https://httpbin.org/basic-auth/${username}/Testing123`;
const creds = {
'auth': {
'user': username,
'pass': password
}
throw error;
});
// Wait for all async task to complete then generate and return a custom auth token.
return Promise.all([userCreationTask]).then(() => {
// Create a Firebase custom auth token.
const token = admin.auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
}
return new Promise((resolve, reject) => {
basicAuthRequest(authEndpoint, creds, (error, response, body) => {
if (error) {
return reject(error)
}
const statusCode = response ? response.statusCode : 0;
if (statusCode === 401) { // Invalid username/password
return resolve(false);
}
if (statusCode !== 200) {
return reject(Error('invalid response returned from ', authEndpoint, ' status code ', statusCode));
}
return resolve(true);
});
});
}

Loading…
Cancel
Save