Created
December 6, 2013 02:23
-
-
Save robwormald/7817593 to your computer and use it in GitHub Desktop.
Sails + passport + oauth2orize stuffs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* AuthController | |
* | |
* @module :: Controller | |
* @description :: Contains logic for handling auth requests. | |
*/ | |
var passport = require('passport'); | |
var GoogleStrategy = require('passport-google').Strategy; | |
module.exports = { | |
process: function(req,res){ | |
//console.log(req) | |
passport.authenticate( | |
'local',{ successReturnToOrRedirect: '/', failureRedirect: '/login' })(req, res); | |
}, | |
signin : function(req,res){ | |
res.view('login') | |
}, | |
googlelogin : function(req,res,next){ | |
passport.authenticate( | |
'google',{ successReturnToOrRedirect: '/', failureRedirect: '/login' })(req, res,next); | |
}, | |
googlecallback : function(req,res,next){ | |
console.log('???') | |
passport.authenticate('google',{ successReturnToOrRedirect: '/', failureRedirect: '/login' })(req, res,next); | |
}, | |
logout: function(req,res){ | |
req.logout(); | |
res.redirect('/'); | |
}, | |
connect : function(req,res){ | |
console.log('authenticated websocket connection') | |
res.json({ping : 'pong'}) | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var passport = require('passport'), | |
BearerStrategy = require('passport-http-bearer').Strategy, | |
BasicStrategy = require('passport-http').BasicStrategy, | |
LocalStrategy = require('passport-local').Strategy, | |
ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy, | |
GoogleOAuth2Strategy = require('passport-google-oauth').OAuth2Strategy; | |
var utils = require('../innitUtils.js'); | |
var fs = require('fs'); | |
var file = 'googleConfig.json'; | |
var _googleConfig = JSON.parse(fs.readFileSync(file, 'utf8')) | |
var serverURL = process.env.URL || "http://localhost:1337" | |
passport.serializeUser(function(user, done) { | |
done(null, user.id); | |
}); | |
passport.deserializeUser(function(id, done) { | |
User.findOne({id:id}, function (err, user) { | |
// if(user.domainKey){} | |
done(err, user); | |
}); | |
}); | |
/** | |
* LocalStrategy | |
* | |
* This strategy is used to authenticate users based on a username and password. | |
* Anytime a request is made to authorize an application, we must ensure that | |
* a user is logged in before asking them to approve the request. | |
*/ | |
passport.use( | |
new LocalStrategy( | |
function (username, password, done) { | |
process.nextTick( | |
function () { | |
User.findOne({ | |
username: username | |
}).done( | |
function (err, user) { | |
if (err) { | |
console.log(err); | |
return; | |
} | |
if (!user) { | |
return done( | |
null, false, { | |
message: 'Unknown user ' + username | |
}); | |
} | |
if (user.validPassword(password)) { | |
return done( | |
null, false, { | |
message: 'Invalid password' | |
}); | |
} | |
return done(null, user); | |
}) | |
}); | |
})); | |
console.log() | |
passport.use(new GoogleOAuth2Strategy({ | |
clientID: _googleConfig.web.client_id, | |
clientSecret: _googleConfig.web.client_secret, | |
callbackURL: process.env.HOST + "/auth/google/callback", | |
offline : true, | |
scope : ["openid","email","https://www.googleapis.com/auth/plus.me","https://www.googleapis.com/auth/admin.directory.user.readonly","https://www.googleapis.com/auth/admin.directory.orgunit.readonly","https://www.googleapis.com/auth/admin.directory.group.readonly","https://www.googleapis.com/auth/admin.directory.device.mobile.readonly","https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly"], | |
passReqToCallback : true | |
}, | |
function(req,accessToken, refreshToken, profile, done) { | |
console.log(accessToken) | |
console.log(refreshToken) | |
console.log(profile) | |
User.findOne({identifier : profile.id},function(err,user){ | |
if (err) { | |
return done(err); | |
} | |
if (!user) { | |
if(profile._json && profile._json.verified_email){ | |
// console.log(profile._json) | |
User.create({ | |
identifier : profile.id, | |
username : profile._json.email, | |
password : utils.uid(16), | |
email : profile._json.email, | |
domain_key : profile._json['hd'], | |
provider : 'google' | |
}).done(function(err,_user){ | |
if(accessToken){ | |
// Token.create({ | |
// user : user.id, | |
// token : accessToken, | |
// refreshToken : refreshToken || null, | |
// provider : 'google' | |
// }).done(function(err,token){ | |
// user.credentials.google = token | |
// return done(null,user) | |
// }) | |
console.log(_user) | |
return done(null,_user) | |
} | |
else{ | |
return done(null,_user) | |
} | |
}) | |
} | |
} | |
else{ | |
return done(null, user); | |
} | |
}) | |
} | |
)); | |
/** | |
* BasicStrategy & ClientPasswordStrategy | |
* | |
* These strategies are used to authenticate registered OAuth clients. They are | |
* employed to protect the `token` endpoint, which consumers use to obtain | |
* access tokens. The OAuth 2.0 specification suggests that clients use the | |
* HTTP Basic scheme to authenticate. Use of the client password strategy | |
* allows clients to send the same credentials in the request body (as opposed | |
* to the `Authorization` header). While this approach is not recommended by | |
* the specification, in practice it is quite common. | |
*/ | |
passport.use(new BasicStrategy( | |
function (username, password, done) { | |
User.findOne({ | |
email: username | |
}, function (err, user) { | |
if (err) { | |
return done(err); | |
} | |
if (!user) { | |
return done(null, false); | |
} | |
if (!user.password != password) { | |
return done(null, false); | |
} | |
return done(null, user); | |
}); | |
})); | |
passport.use(new ClientPasswordStrategy( | |
function (clientId, clientSecret, done) { | |
Client.findOne({ | |
id: clientId | |
}, function (err, client) { | |
if (err) { | |
return done(err); | |
} | |
if (!client) { | |
return done(null, false); | |
} | |
if (client.clientSecret != clientSecret) { | |
return done(null, false); | |
} | |
return done(null, client); | |
}); | |
})); | |
/** | |
* BearerStrategy | |
* | |
* This strategy is used to authenticate users based on an access token (aka a | |
* bearer token). The user must have previously authorized a client | |
* application, which is issued an access token to make requests on behalf of | |
* the authorizing user. | |
*/ | |
passport.use(new BearerStrategy( | |
function(accessToken, done) { | |
Token.findOne({accessToken:accessToken}, function(err, token) { | |
if (err) { return done(err); } | |
if (!token) { return done(null, false); } | |
var info = {scope: '*'} | |
User.findOne({ | |
id: token.user | |
}).done( | |
function (err, user) { | |
User.findOne({ | |
id: token.user | |
},done(err,user,info)); | |
}); | |
}); | |
} | |
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var passport = require('passport'), | |
oauth2orize = require('oauth2orize'), | |
jwtBearer = require('oauth2orize-jwt-bearer').Exchange, | |
login = require('connect-ensure-login'), | |
utils = require('../innitUtils.js'); | |
module.exports = { | |
express: { | |
customMiddleware: function(app) | |
{ | |
/** oAuth Server **/ | |
app.use(passport.initialize()); | |
app.use(passport.session()); | |
var server = oauth2orize.createServer(); | |
// Register supported grant types. | |
// | |
// OAuth 2.0 specifies a framework that allows users to grant client | |
// applications limited access to their protected resources. It does this | |
// through a process of the user granting access, and the client exchanging | |
// the grant for an access token. | |
// Grant authorization codes. The callback takes the `client` requesting | |
// authorization, the `redirectURI` (which is used as a verifier in the | |
// subsequent exchange), the authenticated `user` granting access, and | |
// their response, which contains approved scope, duration, etc. as parsed by | |
// the application. The application issues a code, which is bound to these | |
// values, and will be exchanged for an access token. | |
server.grant(oauth2orize.grant.code(function(client, redirectURI, user, ares, done) { | |
var code = utils.uid(16); | |
Authcode.create({ | |
code: code, | |
client: client.id, | |
redirectURI: redirectURI, | |
user: user.id, | |
scope: ares.scope | |
}).done(function(err,code){ | |
if(err){return done(err,null);} | |
return done(null,code.code); | |
}); | |
})); | |
// Grant implicit authorization. The callback takes the `client` requesting | |
// authorization, the authenticated `user` granting access, and | |
// their response, which contains approved scope, duration, etc. as parsed by | |
// the application. The application issues a token, which is bound to these | |
// values. | |
server.grant(oauth2orize.grant.token(function(client, user, ares, done) { | |
console.log('a') | |
console.log(ares) | |
var token = utils.uid(256); | |
Token.create({ | |
accessToken: token, | |
user: user.id, | |
client: client.id, | |
//scope: code.scope | |
}).done(function(err,token){ | |
if (err) { | |
console.log(err) | |
return done(err); | |
} | |
console.log(token.accessToken) | |
return done(null, token.accessToken); | |
}); | |
})); | |
// Exchange authorization codes for access tokens. The callback accepts the | |
// `client`, which is exchanging `code` and any `redirectURI` from the | |
// authorization request for verification. If these values are validated, the | |
// application issues an access token on behalf of the user who authorized the | |
// code. | |
server.exchange(oauth2orize.exchange.code(function(client, code, redirectURI, done) { | |
Authcode.findOne({ | |
code: code | |
}).done(function(err,code){ | |
if (err || !code) { | |
return done(err); | |
} | |
if (client.id !== code.clientId) { | |
return done(null, false); | |
} | |
if (redirectURI !== code.redirectURI) { | |
return done(null, false); | |
} | |
var token = utils.uid(256); | |
Token.create({ | |
token: token, | |
user: code.user, | |
client: code.client, | |
scope: code.scope | |
}).done(function(err,token){ | |
if (err) { | |
return done(err); | |
} | |
return done(null, token); | |
}); | |
}); | |
})); | |
// Exchange user id and password for access tokens. The callback accepts the | |
// `client`, which is exchanging the user's name and password from the | |
// authorization request for verification. If these values are validated, the | |
// application issues an access token on behalf of the user who authorized the code. | |
server.exchange(oauth2orize.exchange.password(function(client, username, password, scope, done) { | |
console.log('password xchange') | |
//Validate the client | |
Client.findOne({id : client.id}).done(function(err, localClient) { | |
console.log('password xchange') | |
if (err) { return done(err); } | |
if(localClient === null) { | |
return done(null, false); | |
} | |
if(localClient.clientSecret !== client.clientSecret) { | |
return done(null, false); | |
} | |
//Validate the user | |
User.findByUsername(username, function(err, user) { | |
if (err) { return done(err); } | |
if(user === null) { | |
return done(null, false); | |
} | |
if(user.validPassword(password)) { | |
return done(null, false); | |
} | |
//Everything validated, return the token | |
var token = utils.uid(256); | |
Token.create({ | |
token : token, | |
user : user.id, | |
client : client.id | |
}).then(function(err) { | |
if (err) { return done(err); } | |
done(null, token); | |
}); | |
}); | |
}); | |
})); | |
//TODO : google JWT token stuff | |
// server.exchange('urn:ietf:params:oauth:grant-type:jwt-bearer', jwtBearer(function(client, data, signature, done) { | |
// var crypto = require('crypto') | |
// , pub = // TODO - Load your pubKey registered to the client from the file system or database | |
// , verifier = crypto.createVerify("RSA-SHA256"); | |
// verifier.update(JSON.stringify(data)); | |
// if (verifier.verify(pub, signature, 'base64')) { | |
// // TODO - base64url decode data then verify client_id, scope and expiration are valid | |
// AccessToken.create(client, scope, function(err, accessToken) { | |
// if (err) { return done(err); } | |
// done(null, accessToken); | |
// }); | |
// } | |
// })); | |
app.get('/oauth/authorize', login.ensureLoggedIn(), server.authorize(function (clientID, redirectURI, done) { | |
console.log(clientID) | |
Client.findOne({ | |
clientKey: clientID | |
}, function (err, cli) { | |
console.log(cli) | |
if (err) { | |
return done(err); | |
} | |
if (!cli) { | |
return done(null, false); | |
} | |
if (cli.redirectURI != redirectURI) { | |
return done(null, false); | |
} | |
return done(null, cli, cli.redirectURI); | |
}); | |
}), function (req, res) { | |
res.render('dialog', { | |
transactionID: req.oauth2.transactionID, | |
user: req.user, | |
cli: req.oauth2.client | |
}); | |
}); | |
app.post('/oauth/authorize/decision', | |
login.ensureLoggedIn(), | |
server.decision()); | |
server.serializeClient(function(client, done) { | |
return done(null, client.id); | |
}); | |
server.deserializeClient(function(id, done) { | |
Client.findOne(id, function(err, client) { | |
if (err) { return done(err); } | |
return done(null, client); | |
}); | |
}); | |
app.get('/token', | |
passport.authenticate('oauth2-client-password', { session: false }), | |
server.token(), | |
server.errorHandler()); | |
app.get('/tokenInfo',function (req, res) { | |
console.log(req.query) | |
if (req.query.access_token) { | |
Token.find({token : req.query.access_token}).then(function (token) { | |
console.log(token) | |
if (!token) { | |
res.status(400); | |
res.json({ error: "invalid_token" }); | |
} else if(new Date() > token.expirationDate) { | |
res.status(400); | |
res.json({ error: "invalid_token" }); | |
} | |
else { | |
Client.find(token.client, function (err, client) { | |
if (err || !client) { | |
res.status(400); | |
res.json({ error: "invalid_token"}); | |
} else { | |
if(token.expirationDate) { | |
var expirationLeft = Math.floor((token.expirationDate.getTime() - new Date().getTime()) / 1000); | |
if(expirationLeft <= 0) { | |
res.json({ error: "invalid_token"}); | |
} else { | |
res.json({ audience: client.id, expires_in: expirationLeft}); | |
} | |
} else { | |
console.log('woohoo?') | |
res.json({validToken: true }) | |
} | |
} | |
}); | |
} | |
}); | |
} else { | |
res.status(400); | |
res.json({ error: "invalid_token"}); | |
} | |
}) | |
//this function is only to test callbacks | |
app.get('/testCallback',function(req,res){ | |
res.render('test',{params:req.query}); | |
}); | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment