@quarks/quarks-iam
Version:
A modern authorization server built to authenticate your users and protect your APIs
536 lines (394 loc) • 14.7 kB
text/coffeescript
chai = require 'chai'
sinon = require 'sinon'
sinonChai = require 'sinon-chai'
expect = chai.expect
chai.use sinonChai
chai.should()
IDToken = require '../../../models/IDToken'
AccessToken = require '../../../models/AccessToken'
AuthorizationCode = require '../../../models/AuthorizationCode'
authorize = require('../../../oidc').authorize
describe 'Authorize', ->
{req,res,next,err} = {}
describe 'with consent and "code" response type', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
req =
session: {}
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code'
redirect_uri: 'https://host/callback'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
it 'should set default max_age if none is provided', ->
AuthorizationCode.insert.should.have.been.calledWith sinon.match({
max_age: undefined
})
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a query string', ->
res.redirect.should.have.been.calledWith sinon.match('?')
it 'should provide authorization code', ->
res.redirect.should.have.been.calledWith sinon.match 'code=1234'
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match 'state=r4nd0m'
it 'should not provide session_state', ->
res.redirect.should.not.have.been.calledWith sinon.match('session_state=')
describe 'with consent and "code" response type and "max_age" param', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
req =
session: {}
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code'
redirect_uri: 'https://host/callback'
state: 'r4nd0m'
max_age: 1000
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
it 'should set max_age from params', ->
AuthorizationCode.insert.should.have.been.calledWith sinon.match({
max_age: req.connectParams.max_age
})
describe 'with consent and "code" response type and client "default_max_age"', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
req =
session: {}
client:
_id: 'uuid1'
default_max_age: 2000
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code'
redirect_uri: 'https://host/callback'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
it 'should set max_age from client default_max_age', ->
AuthorizationCode.insert.should.have.been.calledWith sinon.match({
max_age: req.client.default_max_age
})
describe 'with consent and "code token" response type', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
response = AccessToken.initialize().project('issue')
sinon.stub(AccessToken, 'issue').callsArgWith(1, null, response)
req =
session: {}
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code token'
redirect_uri: 'https://host/callback'
scope: 'openid profile'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
AccessToken.issue.restore()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a uri fragment', ->
res.redirect.should.have.been.calledWith sinon.match('#')
it 'should provide authorization code', ->
res.redirect.should.have.been.calledWith sinon.match 'code=1234'
it 'should provide access_token', ->
res.redirect.should.have.been.calledWith sinon.match('access_token=')
it 'should provide token_type', ->
res.redirect.should.have.been.calledWith sinon.match('token_type=Bearer')
it 'should provide expires_in', ->
res.redirect.should.have.been.calledWith sinon.match('expires_in=3600')
it 'should not provide id_token', ->
res.redirect.should.not.have.been.calledWith sinon.match('id_token=')
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match req.connectParams.state
it 'should provide session_state', ->
res.redirect.should.have.been.calledWith sinon.match('session_state=')
describe 'with consent and "code id_token" response type', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
sinon.spy(IDToken.prototype, 'initializePayload')
req =
session:
amr: ['sms', 'otp']
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code id_token'
redirect_uri: 'https://host/callback'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
IDToken.prototype.initializePayload.restore()
it 'should set default max_age if none is provided', ->
AuthorizationCode.insert.should.have.been.calledWith sinon.match({
max_age: undefined
})
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a uri fragment', ->
res.redirect.should.have.been.calledWith sinon.match('#')
it 'should provide authorization code', ->
res.redirect.should.have.been.calledWith sinon.match 'code=1234'
it 'should provide id_token', ->
res.redirect.should.have.been.calledWith sinon.match('id_token=')
it 'should not provide access_token', ->
res.redirect.should.not.have.been.calledWith sinon.match('access_token=')
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match 'state=r4nd0m'
it 'should provide session_state', ->
res.redirect.should.have.been.calledWith sinon.match('session_state=')
it 'should include `amr` claim in id_token', ->
IDToken.prototype.initializePayload.should.have.been.calledWith(
sinon.match amr: req.session.amr
)
describe 'with consent and "id_token token" response type', ->
before (done) ->
response = AccessToken.initialize().project('issue')
sinon.stub(AccessToken, 'issue').callsArgWith(1, null, response)
sinon.spy(IDToken.prototype, 'initializePayload')
req =
session:
amr: ['otp']
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'id_token token'
redirect_uri: 'https://host/callback'
nonce: 'n0nc3'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AccessToken.issue.restore()
IDToken.prototype.initializePayload.restore()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a uri fragment', ->
res.redirect.should.have.been.calledWith sinon.match('#')
it 'should provide access_token', ->
res.redirect.should.have.been.calledWith sinon.match('access_token=')
it 'should provide token_type', ->
res.redirect.should.have.been.calledWith sinon.match('token_type=Bearer')
it 'should provide expires_in', ->
res.redirect.should.have.been.calledWith sinon.match('expires_in=3600')
it 'should provide id_token', ->
res.redirect.should.have.been.calledWith sinon.match('id_token=')
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match req.connectParams.state
it 'should provide session_state', ->
res.redirect.should.have.been.calledWith sinon.match('session_state=')
it 'should include `amr` claim in id_token', ->
IDToken.prototype.initializePayload.should.have.been.calledWith(
sinon.match amr: req.session.amr
)
describe 'with consent and "code id_token token" response type', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
response = AccessToken.initialize().project('issue')
sinon.stub(AccessToken, 'issue').callsArgWith(1, null, response)
sinon.spy(IDToken.prototype, 'initializePayload')
req =
session:
amr: ['pwd']
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'code id_token token'
redirect_uri: 'https://host/callback'
scope: 'openid profile'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
AccessToken.issue.restore()
IDToken.prototype.initializePayload.restore()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a uri fragment', ->
res.redirect.should.have.been.calledWith sinon.match('#')
it 'should provide authorization code', ->
res.redirect.should.have.been.calledWith sinon.match 'code=1234'
it 'should provide access_token', ->
res.redirect.should.have.been.calledWith sinon.match('access_token=')
it 'should provide token_type', ->
res.redirect.should.have.been.calledWith sinon.match('token_type=Bearer')
it 'should provide expires_in', ->
res.redirect.should.have.been.calledWith sinon.match('expires_in=3600')
it 'should provide id_token', ->
res.redirect.should.have.been.calledWith sinon.match('id_token=')
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match req.connectParams.state
it 'should provide session_state', ->
res.redirect.should.have.been.calledWith sinon.match('session_state=')
it 'should include `amr` claim in id_token', ->
IDToken.prototype.initializePayload.should.have.been.calledWith(
sinon.match amr: req.session.amr
)
describe 'with consent and "none" response type', ->
before (done) ->
sinon.stub(AuthorizationCode, 'insert').callsArgWith(1, null, {
code: '1234'
})
req =
session: {}
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'none'
redirect_uri: 'https://host/callback'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AuthorizationCode.insert.restore()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a query string', ->
res.redirect.should.have.been.calledWith sinon.match('?')
it 'should not provide authorization code', ->
res.redirect.should.not.have.been.calledWith sinon.match 'code=1234'
it 'should provide state', ->
res.redirect.should.have.been.calledWith sinon.match 'state=r4nd0m'
it 'should not provide session_state', ->
res.redirect.should.not.have.been.calledWith sinon.match('session_state=')
describe 'with consent and response mode param', ->
before (done) ->
response = AccessToken.initialize().project('issue')
sinon.stub(AccessToken, 'issue').callsArgWith(1, null, response)
req =
session: {}
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
authorize: 'true'
response_type: 'id_token token'
response_mode: 'query'
redirect_uri: 'https://host/callback'
nonce: 'n0nc3'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
after ->
AccessToken.issue.restore()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide a query string', ->
res.redirect.should.have.been.calledWith sinon.match('?')
describe 'without consent', ->
before (done) ->
req =
client:
_id: 'uuid1'
user:
_id: 'uuid2'
connectParams:
response_type: 'id_token token'
redirect_uri: 'https://host/callback'
nonce: 'n0nc3'
state: 'r4nd0m'
res =
redirect: sinon.spy()
next = sinon.spy()
authorize req, res, next
done()
it 'should redirect to the redirect_uri', ->
res.redirect.should.have.been.calledWith sinon.match(
req.connectParams.redirect_uri
)
it 'should provide an "access_denied" error', ->
res.redirect.should.have.been.calledWith sinon.match('error=access_denied')