Commit c139c6db authored by Gergely Ujvari's avatar Gergely Ujvari

Introduce auth service

- Bridge the for identity service
- Handles login, logout, and exposes the current logged in user
- permits function for authorizing actions
parent 87f2b942
class AccountController
@inject = [ '$scope', '$filter',
'flash', 'formHelpers', 'identity', 'session', 'user']
'flash', 'formHelpers', 'identity', 'session', 'auth']
constructor: ($scope, $filter,
flash, formHelpers, identity, session, user ) ->
flash, formHelpers, identity, session, auth ) ->
persona_filter = $filter('persona')
$scope.subscriptionDescription =
reply: 'Receive notification emails when: - Someone replies to one of my annotations'
......@@ -33,7 +33,7 @@ class AccountController
$scope.$broadcast 'formState', form.$name, '' # Update status btn
$scope.tab = 'Account'
session.profile({user_id: user.getPersona()}).$promise
session.profile({user_id: auth.user}).$promise
.then (result) =>
$scope.subscriptions = result.subscriptions
......@@ -47,7 +47,7 @@ class AccountController
# The extension is then removed from the page.
# Confirmation of success is given.
return unless form.$valid
username = persona_filter user.getPersona()
username = persona_filter auth.user
packet =
username: username
pwd: form.pwd.$modelValue
......@@ -62,7 +62,7 @@ class AccountController
formHelpers.applyValidationErrors(form)
return unless form.$valid
username = persona_filter user.getPersona()
username = persona_filter auth.user
packet =
username: username
pwd: form.pwd.$modelValue
......@@ -77,7 +77,7 @@ class AccountController
$scope.updated = (index, form) ->
packet =
username: user.getPersona()
username: auth.user
subscriptions: JSON.stringify $scope.subscriptions[index]
successHandler = angular.bind(null, onSuccess, form)
......
......@@ -2,17 +2,15 @@ class AppController
this.$inject = [
'$location', '$route', '$scope', '$timeout',
'annotator', 'flash', 'identity', 'streamer', 'streamfilter',
'documentHelpers', 'drafts', 'user'
'documentHelpers', 'drafts', 'auth'
]
constructor: (
$location, $route, $scope, $timeout,
annotator, flash, identity, streamer, streamfilter,
documentHelpers, drafts, user
documentHelpers, drafts, auth
) ->
{plugins, host, providers} = annotator
isFirstRun = $location.search().hasOwnProperty('firstrun')
applyUpdates = (action, data) ->
"""Update the application with new data from the websocket."""
return unless data?.length
......@@ -54,7 +52,7 @@ class AppController
Store = plugins.Store
delete plugins.Store
if user.getPersona() or annotator.socialView.name is 'none'
if auth.user or annotator.socialView.name is 'none'
annotator.addPlugin 'Store', annotator.options.Store
$scope.store = plugins.Store
......@@ -79,12 +77,12 @@ class AppController
Store.updateAnnotation = angular.noop
# Sort out which annotations should remain in place.
persona = user.getPersona()
persona = auth.user
view = annotator.socialView.name
cull = (acc, annotation) ->
if view is 'single-player' and annotation.user != persona
acc.drop.push annotation
else if authorizeAction 'read', annotation, persona
else if auth.permits 'read', annotation, persona
acc.keep.push annotation
else
acc.drop.push annotation
......@@ -127,9 +125,11 @@ class AppController
$scope.dialog.visible = false
reset = ->
$scope.persona = user.getPersona()
$scope.persona = auth.user
$scope.dialog.visible = false
firstRun = false
# Update any edits in progress.
for draft in drafts.all()
annotator.publish 'beforeAnnotationCreated', draft
......@@ -139,12 +139,10 @@ class AppController
streamer.close()
streamer.open()
identity.watch {onlogin, onlogout, onready}
$scope.$watch 'socialView.name', (newValue, oldValue) ->
return if newValue is oldValue
initStore()
if newValue is 'single-player' and not user.getPersona()
if newValue is 'single-player' and not auth.user
annotator.show()
flash 'info',
'You will need to sign in for your highlights to be saved.'
......@@ -158,7 +156,7 @@ class AppController
$scope.sort = {name, predicate}
$scope.$watch 'store.entities', (entities, oldEntities) ->
return if entities is oldEntities
return if entities is oldEntities or not entities
if entities.length
streamfilter
......@@ -169,12 +167,12 @@ class AppController
$scope.login = ->
$scope.dialog.visible = true
identity.request {oncancel}
auth.login().then(reset, oncancel)
$scope.logout = ->
return unless drafts.discard()
$scope.dialog.visible = false
identity.logout()
auth.logout().then(reset)
$scope.loadMore = (number) ->
unless streamfilter.getPastData().hits then return
......@@ -203,6 +201,11 @@ class AppController
$scope.sort = name: 'Location'
$scope.threading = plugins.Threading
auth.getInitialUser().then(reset, ->
reset()
$scope.login()
)
class AnnotationViewerController
this.$inject = [
......
......@@ -38,9 +38,9 @@ validate = (value) ->
###
AnnotationController = [
'$scope', '$timeout',
'annotator', 'drafts', 'flash', 'documentHelpers', 'timeHelpers', 'user'
'annotator', 'drafts', 'flash', 'documentHelpers', 'timeHelpers', 'auth'
($scope, $timeout,
annotator, drafts, flash, documentHelpers, timeHelpers, user
annotator, drafts, flash, documentHelpers, timeHelpers, auth
) ->
@annotation = {}
@action = 'view'
......@@ -182,17 +182,16 @@ AnnotationController = [
reply = {references, uri}
annotator.publish 'beforeAnnotationCreated', reply
persona = user.getPersona()
if persona?
reply.permissions.update = [persona]
reply.permissions.delete = [persona]
reply.permissions.admin = [persona]
if auth.user?
reply.permissions.update = [auth.user]
reply.permissions.delete = [auth.user]
reply.permissions.admin = [auth.user]
# If replying to a public annotation make the response public.
if 'group:__world__' in (model.permissions.read or [])
reply.permissions.read = ['group:__world__']
else
reply.permissions.read = [persona]
reply.permissions.read = [auth.user]
###*
# @ngdoc method
......
LOGIN_REQUEST = 'login'
LOGOUT_REQUEST = 'logout'
INITIAL_REQUEST = 'initial'
pendingRequests =
login: []
logout: []
initial: []
resolvePendingRequests = (requestType, user) ->
for request in pendingRequests[requestType]
request.resolve user if request.resolve?
pendingRequests[requestType] = []
rejectPendingRequests = (requestType, reason) ->
for request in pendingRequests[requestType]
request.reject reason if request.reject?
pendingRequests[requestType] = []
class Auth
_checkingToken: false
login: null
logout: null
getInitialUser: null
user: null
this.$inject = ['$location', '$q',
'annotator', 'documentHelpers', 'identity']
constructor: ( $location, $q,
annotator, documentHelpers, identity) ->
{plugins} = annotator
@login = ->
oncancel = ->
rejectPendingRequests LOGIN_REQUEST, null
deferred = $q.defer()
pendingRequests[LOGIN_REQUEST].push deferred
identity.request({oncancel})
deferred.promise
@logout = ->
deferred = $q.defer()
identity.logout()
pendingRequests[LOGOUT_REQUEST].push deferred
deferred.promise
@getInitialUser = ->
deferred = $q.defer()
pendingRequests[INITIAL_REQUEST].push deferred
deferred.promise
onlogin = (assertion) =>
@_checkingToken = true
# Configure the Auth plugin with the issued assertion as refresh token.
annotator.addPlugin 'Auth',
tokenUrl: documentHelpers.absoluteURI(
"/api/token?assertion=#{assertion}")
# Set the user from the token.
plugins.Auth.withToken (token) =>
@_checkingToken = false
annotator.addPlugin 'Permissions',
user: token.userId
userAuthorize: @permits
@user = token.userId
resolvePendingRequests INITIAL_REQUEST, @user
resolvePendingRequests LOGIN_REQUEST, @user
onlogout = =>
plugins.Auth?.element.removeData('annotator:headers')
plugins.Auth?.destroy()
delete plugins.Auth
plugins.Permissions?.setUser(null)
plugins.Permissions?.destroy()
delete plugins.Permissions
@user = null
@_checkingToken = false
resolvePendingRequests LOGOUT_REQUEST, @user
onready = =>
if not @_checkingToken
rejectPendingRequests INITIAL_REQUEST, null
identity.watch {onlogin, onlogout, onready}
# User authorization function for the Permissions plugin.
permits: (action, annotation, user) ->
if annotation.permissions
tokens = annotation.permissions[action] || []
if tokens.length == 0
# Empty or missing tokens array: only admin can perform action.
return false
for token in tokens
if user == token
return true
if token == 'group:__world__'
return true
# No tokens matched: action should not be performed.
return false
# Coarse-grained authorization
else if annotation.user
return user and user == annotation.user
# No authorization info on annotation: free-for-all!
true
angular.module('h')
.service('auth', Auth)
# User authorization function for the Permissions plugin.
authorizeAction = (action, annotation, user) ->
if annotation.permissions
tokens = annotation.permissions[action] || []
if tokens.length == 0
# Empty or missing tokens array: only admin can perform action.
return false
for token in tokens
if user == token
return true
if token == 'group:__world__'
return true
# No tokens matched: action should not be performed.
return false
# Coarse-grained authorization
else if annotation.user
return user and user == annotation.user
# No authorization info on annotation: free-for-all!
true
class User
_persona: undefined
_checkingToken: false
login: undefined
logout: undefined
this.$inject = ['annotator', 'documentHelpers']
constructor: ( annotator, documentHelpers) ->
{plugins} = annotator
@login = (assertion, callbackFn) ->
@_checkingToken = true
# Configure the Auth plugin with the issued assertion as refresh token.
annotator.addPlugin 'Auth',
tokenUrl: documentHelpers.absoluteURI(
"/api/token?assertion=#{assertion}")
# Set the user from the token.
plugins.Auth.withToken (token) =>
@_checkingToken = false
annotator.addPlugin 'Permissions',
user: token.userId
userAuthorize: authorizeAction
@_persona = token.userId
callbackFn()
@logout = ->
plugins.Auth?.element.removeData('annotator:headers')
plugins.Auth?.destroy()
delete plugins.Auth
plugins.Permissions?.setUser(null)
plugins.Permissions?.destroy()
delete plugins.Permissions
@_persona = null
@_checkingToken = false
checkingInProgress: -> @_checkingToken
getPersona: -> @_persona
noPersona: -> @_persona = null
angular.module('h')
.service('user', User)
\ No newline at end of file
......@@ -8,7 +8,7 @@ describe 'h.account.AccountController', ->
fakeSession = null
fakeIdentity = null
fakeFormHelpers = null
fakeUser = null
fakeAuth = null
editProfilePromise = null
disableUserPromise = null
profilePromise = null
......@@ -23,7 +23,7 @@ describe 'h.account.AccountController', ->
logout: sandbox.spy()
fakeFormHelpers =
applyValidationErrors: sandbox.spy()
fakeUser =
fakeAuth =
getPersona: (-> 'egon@columbia.edu')
$filterProvider.register 'persona', ->
......@@ -33,7 +33,7 @@ describe 'h.account.AccountController', ->
$provide.value 'flash', fakeFlash
$provide.value 'identity', fakeIdentity
$provide.value 'formHelpers', fakeFormHelpers
$provide.value 'user', fakeUser
$provide.value 'auth', fakeAuth
return
beforeEach inject ($rootScope, $q, $controller) ->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment