mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #1047 from sharelatex/ew-oauth-authorization
add oauth middlewear GitOrigin-RevId: b68360763e1060fdbcbb4348d3d691a803fbfa41
This commit is contained in:
parent
0cfb765501
commit
365158f283
5 changed files with 120 additions and 0 deletions
|
@ -13,6 +13,8 @@ Analytics = require "../Analytics/AnalyticsManager"
|
|||
passport = require 'passport'
|
||||
NotificationsBuilder = require("../Notifications/NotificationsBuilder")
|
||||
SudoModeHandler = require '../SudoMode/SudoModeHandler'
|
||||
V1Api = require "../V1/V1Api"
|
||||
{User} = require "../../models/User"
|
||||
|
||||
module.exports = AuthenticationController =
|
||||
|
||||
|
@ -169,6 +171,24 @@ module.exports = AuthenticationController =
|
|||
|
||||
return doRequest
|
||||
|
||||
requireOauth: () ->
|
||||
return (req, res, next = (error) ->) ->
|
||||
return res.status(401).send() unless req.token?
|
||||
options =
|
||||
expectedStatusCodes: [401]
|
||||
json: token: req.token
|
||||
method: "POST"
|
||||
uri: "/api/v1/sharelatex/oauth_authorize"
|
||||
V1Api.request options, (error, response, body) ->
|
||||
return next(error) if error?
|
||||
return res.status(401).json({error: "invalid_token"}) unless body?.user_profile?.id
|
||||
User.findOne { "overleaf.id": body.user_profile.id }, (error, user) ->
|
||||
return next(error) if error?
|
||||
return res.status(401).send() unless user?
|
||||
req.oauth = access_token: body.access_token
|
||||
req.oauth_user = user
|
||||
next()
|
||||
|
||||
_globalLoginWhitelist: []
|
||||
addEndpointToLoginWhitelist: (endpoint) ->
|
||||
AuthenticationController._globalLoginWhitelist.push endpoint
|
||||
|
|
|
@ -20,6 +20,7 @@ methodOverride = require('method-override')
|
|||
csrf = require('csurf')
|
||||
csrfProtection = csrf()
|
||||
cookieParser = require('cookie-parser')
|
||||
bearerToken = require('express-bearer-token')
|
||||
|
||||
# Init the session store
|
||||
sessionStore = new RedisStore(client:sessionsRedisClient)
|
||||
|
@ -71,6 +72,7 @@ app.use bodyParser.urlencoded({ extended: true, limit: "2mb"})
|
|||
app.use bodyParser.json({limit: Settings.max_doc_length + 64 * 1024}) # 64kb overhead
|
||||
app.use multer(dest: Settings.path.uploadFolder)
|
||||
app.use methodOverride()
|
||||
app.use bearerToken()
|
||||
|
||||
app.use metrics.http.monitor(logger)
|
||||
RedirectManager.apply(webRouter)
|
||||
|
|
5
services/web/npm-shrinkwrap.json
generated
5
services/web/npm-shrinkwrap.json
generated
|
@ -3332,6 +3332,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"express-bearer-token": {
|
||||
"version": "2.2.0",
|
||||
"from": "express-bearer-token@>=2.2.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/express-bearer-token/-/express-bearer-token-2.2.0.tgz"
|
||||
},
|
||||
"express-http-proxy": {
|
||||
"version": "1.1.0",
|
||||
"from": "express-http-proxy@>=1.1.0 <2.0.0",
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"dateformat": "1.0.4-1.2.3",
|
||||
"daterangepicker": "^2.1.27",
|
||||
"express": "4.13.0",
|
||||
"express-bearer-token": "^2.2.0",
|
||||
"express-http-proxy": "^1.1.0",
|
||||
"express-session": "^1.14.2",
|
||||
"fs-extra": "^4.0.2",
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
sinonChai = require "sinon-chai"
|
||||
chai.use sinonChai
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Authentication/AuthenticationController.js"
|
||||
|
@ -13,6 +15,7 @@ ObjectId = require("mongojs").ObjectId
|
|||
describe "AuthenticationController", ->
|
||||
beforeEach ->
|
||||
tk.freeze(Date.now())
|
||||
@UserModel = findOne: sinon.stub()
|
||||
@AuthenticationController = SandboxedModule.require modulePath, requires:
|
||||
"./AuthenticationManager": @AuthenticationManager = {}
|
||||
"../User/UserUpdater" : @UserUpdater = {updateUser:sinon.stub()}
|
||||
|
@ -32,6 +35,8 @@ describe "AuthenticationController", ->
|
|||
"../SudoMode/SudoModeHandler": @SudoModeHandler = {activateSudoMode: sinon.stub().callsArgWith(1, null)}
|
||||
"../Notifications/NotificationsBuilder": @NotificationsBuilder =
|
||||
ipMatcherAffiliation: sinon.stub()
|
||||
"../V1/V1Api": @V1Api = request: sinon.stub()
|
||||
"../../models/User": { User: @UserModel }
|
||||
@user =
|
||||
_id: ObjectId()
|
||||
email: @email = "USER@example.com"
|
||||
|
@ -395,6 +400,93 @@ describe "AuthenticationController", ->
|
|||
it "should redirect to the register or login page", ->
|
||||
@AuthenticationController._redirectToLoginOrRegisterPage.calledWith(@req, @res).should.equal true
|
||||
|
||||
describe "requireOauth", ->
|
||||
beforeEach ->
|
||||
@res.send = sinon.stub()
|
||||
@res.status = sinon.stub().returns(@res)
|
||||
@middleware = @AuthenticationController.requireOauth()
|
||||
|
||||
describe "when token not provided", ->
|
||||
beforeEach ->
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should return 401 error", ->
|
||||
@res.status.should.have.been.calledWith 401
|
||||
|
||||
describe "when token provided", ->
|
||||
beforeEach ->
|
||||
@V1Api.request = sinon.stub().yields("error", {}, {})
|
||||
@req.token = "foo"
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should make request to v1 api with token", ->
|
||||
@V1Api.request.should.have.been.calledWith {
|
||||
expectedStatusCodes: [401]
|
||||
json: token: "foo"
|
||||
method: "POST"
|
||||
uri: "/api/v1/sharelatex/oauth_authorize"
|
||||
}
|
||||
|
||||
describe "when v1 api returns error", ->
|
||||
beforeEach ->
|
||||
@V1Api.request = sinon.stub().yields("error", {}, {})
|
||||
@req.token = "foo"
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should return status", ->
|
||||
@next.should.have.been.calledWith "error"
|
||||
|
||||
describe "when v1 api status code is not 200", ->
|
||||
beforeEach ->
|
||||
@V1Api.request = sinon.stub().yields(null, {statusCode: 401}, {})
|
||||
@req.token = "foo"
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should return status", ->
|
||||
@res.status.should.have.been.calledWith 401
|
||||
|
||||
describe "when v1 api returns authorized profile and access token", ->
|
||||
beforeEach ->
|
||||
@oauth_authorize =
|
||||
access_token: "access_token"
|
||||
user_profile: id: "overleaf-id"
|
||||
@V1Api.request = sinon.stub().yields(null, {statusCode: 200}, @oauth_authorize)
|
||||
@req.token = "foo"
|
||||
|
||||
describe "in all cases", ->
|
||||
beforeEach ->
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should find user", ->
|
||||
@UserModel.findOne.should.have.been.calledWithMatch { "overleaf.id": "overleaf-id" }
|
||||
|
||||
describe "when user find returns error", ->
|
||||
beforeEach ->
|
||||
@UserModel.findOne = sinon.stub().yields("error")
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should return error", ->
|
||||
@next.should.have.been.calledWith "error"
|
||||
|
||||
describe "when user is not found", ->
|
||||
beforeEach ->
|
||||
@UserModel.findOne = sinon.stub().yields(null, null)
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should return unauthorized", ->
|
||||
@res.status.should.have.been.calledWith 401
|
||||
|
||||
describe "when user is found", ->
|
||||
beforeEach ->
|
||||
@UserModel.findOne = sinon.stub().yields(null, "user")
|
||||
@middleware(@req, @res, @next)
|
||||
|
||||
it "should add user to request", ->
|
||||
@req.oauth_user.should.equal "user"
|
||||
|
||||
it "should add access_token to request", ->
|
||||
@req.oauth.access_token.should.equal "access_token"
|
||||
|
||||
describe "requireGlobalLogin", ->
|
||||
beforeEach ->
|
||||
@req.headers = {}
|
||||
|
|
Loading…
Reference in a new issue