Commit c07ea769 authored by Randall Leeds's avatar Randall Leeds

Switch to BrowserID "Goldilocks" API

Rather than support the fiddly matrix of possiblities when a user
may not have a session with the application but has a session with
the identity provider, borrow the newer "Goldilocks" API design from
upstream where the application is responsible for its own session
and the BrowserId implementation is less stateful.
parent 30d2c5dd
...@@ -14,12 +14,11 @@ configure = [ ...@@ -14,12 +14,11 @@ configure = [
identityProvider.checkAuthentication = [ identityProvider.checkAuthentication = [
'$q', 'session', '$q', 'session',
($q, session) -> ($q, session) ->
(authCheck = $q.defer()) (authCheck = $q.defer()).promise.then do ->
.promise.then do ->
session.load().$promise.then (data) -> session.load().$promise.then (data) ->
authCheck.resolve if data.userid then authCheck.resolve data.csrf
certificate: data.csrf else authCheck.reject 'no session'
userid: data.userid , -> authCheck.reject 'request failure'
] ]
identityProvider.forgetAuthentication = [ identityProvider.forgetAuthentication = [
...@@ -31,16 +30,10 @@ configure = [ ...@@ -31,16 +30,10 @@ configure = [
identityProvider.requestAuthentication = [ identityProvider.requestAuthentication = [
'$q', '$rootScope', '$q', '$rootScope',
($q, $rootScope) -> ($q, $rootScope) ->
if authCheck then authCheck.reject() (authCheck = $q.defer()).promise.finally do ->
(authCheck = $q.defer())
.promise.finally do ->
$rootScope.$on 'auth', (event, err, data) -> $rootScope.$on 'auth', (event, err, data) ->
if err if err then authCheck.reject err
authCheck.reject(err) else authCheck.resolve data.csrf
else
authCheck.resolve
certificate: data.csrf
userid: data.userid
] ]
] ]
......
...@@ -27,25 +27,16 @@ authorizeAction = (action, annotation, user) -> ...@@ -27,25 +27,16 @@ authorizeAction = (action, annotation, user) ->
class AppController class AppController
this.$inject = [ this.$inject = [
'$location', '$q', '$route', '$scope', '$timeout', '$location', '$q', '$route', '$scope', '$timeout',
'annotator', 'flash', 'identity', 'socket', 'streamfilter', 'annotator', 'flash', 'identity', 'session', 'socket', 'streamfilter',
'documentHelpers', 'drafts' 'documentHelpers', 'drafts'
] ]
constructor: ( constructor: (
$location, $q, $route, $scope, $timeout $location, $q, $route, $scope, $timeout
annotator, flash, identity, socket, streamfilter, annotator, flash, identity, session, socket, streamfilter,
documentHelpers, drafts documentHelpers, drafts
) -> ) ->
{plugins, host, providers} = annotator {plugins, host, providers} = annotator
# Verified user id.
# Undefined means we don't track the session, but the identity module will
# tell us the state of the session. A null value means that the session
# has been checked and it was found that there is no user logged in.
loggedInUser = undefined
# Resolved once the API service has been discovered.
storeReady = $q.defer()
applyUpdates = (action, data) -> applyUpdates = (action, data) ->
"""Update the application with new data from the websocket.""" """Update the application with new data from the websocket."""
return unless data?.length return unless data?.length
...@@ -62,30 +53,6 @@ class AppController ...@@ -62,30 +53,6 @@ class AppController
plugins.Store?.unregisterAnnotation(annotation) plugins.Store?.unregisterAnnotation(annotation)
annotator.deleteAnnotation(annotation) annotator.deleteAnnotation(annotation)
initIdentity = (persona) ->
"""Initialize identity callbacks."""
# Store the argument as the claimed user id.
claimedUser = persona
# Convert it to the format used by persona.
if claimedUser then claimedUser = claimedUser.replace(/^acct:/, '')
if claimedUser is loggedInUser
if loggedInUser is undefined
# This is the first execution.
# Configure the identity callbacks and the initial user id claim.
identity.watch
loggedInUser: claimedUser
onlogin: (assertion) ->
onlogin(assertion)
onlogout: ->
onlogout()
else if drafts.discard()
if claimedUser
identity.request()
else
identity.logout()
initStore = -> initStore = ->
"""Initialize the storage component.""" """Initialize the storage component."""
Store = plugins.Store Store = plugins.Store
...@@ -198,9 +165,6 @@ class AppController ...@@ -198,9 +165,6 @@ class AppController
_dfdSock.promise _dfdSock.promise
oncancel = ->
loggedInuser = null
onlogin = (assertion) -> onlogin = (assertion) ->
# Configure the Auth plugin with the issued assertion as refresh token. # Configure the Auth plugin with the issued assertion as refresh token.
annotator.addPlugin 'Auth', annotator.addPlugin 'Auth',
...@@ -217,7 +181,7 @@ class AppController ...@@ -217,7 +181,7 @@ class AppController
update: [token.userId] update: [token.userId]
delete: [token.userId] delete: [token.userId]
admin: [token.userId] admin: [token.userId]
loggedInUser = token.userId.replace /^acct:/, '' $scope.persona = token.userId
reset() reset()
onlogout = -> onlogout = ->
...@@ -231,9 +195,18 @@ class AppController ...@@ -231,9 +195,18 @@ class AppController
plugins.Permissions?.destroy() plugins.Permissions?.destroy()
delete plugins.Permissions delete plugins.Permissions
loggedInUser = null $scope.persona = null
reset() reset()
onready = ->
$scope.$evalAsync ->
$scope.persona ?= null
oncancel = ->
$scope.$evalAsync ->
flash 'info', 'Sign in canceled.'
$scope.dialog.visible = false
reset = -> reset = ->
# Do not rely on the identity service to invoke callbacks within an # Do not rely on the identity service to invoke callbacks within an
# angular digest cycle. # angular digest cycle.
...@@ -244,14 +217,6 @@ class AppController ...@@ -244,14 +217,6 @@ class AppController
for draft in drafts.all() for draft in drafts.all()
annotator.publish 'beforeAnnotationCreated', draft annotator.publish 'beforeAnnotationCreated', draft
# Convert the verified user id to the format used by the API.
persona = loggedInUser
if persona then persona = "acct:#{persona}"
# Ensure it is synchronized on the scope.
# Without this, failed identity changes will remain on the scope.
$scope.persona = persona
# Reload services # Reload services
storeReady.promise.then -> initStore() storeReady.promise.then -> initStore()
initUpdater() initUpdater()
...@@ -261,7 +226,7 @@ class AppController ...@@ -261,7 +226,7 @@ class AppController
angular.extend annotator.options.Store, options angular.extend annotator.options.Store, options
storeReady.resolve() storeReady.resolve()
$scope.$watch 'persona', initIdentity identity.watch {onlogin, onlogout, onready}
$scope.$watch 'socialView.name', (newValue, oldValue) -> $scope.$watch 'socialView.name', (newValue, oldValue) ->
return if newValue is oldValue return if newValue is oldValue
......
...@@ -57,42 +57,8 @@ identityProvider = -> ...@@ -57,42 +57,8 @@ identityProvider = ->
'$injector', '$q', '$injector', '$q',
($injector, $q) -> ($injector, $q) ->
provider = this provider = this
loggedInUser = undefined
oncancel = null
onlogin = null onlogin = null
onlogout = null onlogout = null
onmatch = null
onready = null
invokeCallbacks = (grant={}) ->
{userid, certificate} = grant
userid or= null
# Fire callbacks as appropriate.
# Consult the state matrix in the `navigator.id.watch` documentation.
# https://developer.mozilla.org/en-US/docs/Web/API/navigator.id.watch
if loggedInUser is null
if userid
loggedInUser = userid
onlogin?(certificate)
else
onmatch?()
else if loggedInUser
if userid
if loggedInUser is userid
onmatch?()
else
loggedInUser = userid
onlogin?(certificate)
else
loggedInUser = null
onlogout?()
else
if userid
loggedInUser = userid
onlogin?(certificate)
else
loggedInUser = null
onlogout?()
###* ###*
# @ngdoc method # @ngdoc method
...@@ -102,7 +68,7 @@ identityProvider = -> ...@@ -102,7 +68,7 @@ identityProvider = ->
### ###
logout: -> logout: ->
result = $injector.invoke(provider.forgetAuthentication, provider) result = $injector.invoke(provider.forgetAuthentication, provider)
$q.when(result).finally(invokeCallbacks) $q.when(result).finally(onlogout)
###* ###*
# @ngdoc method # @ngdoc method
...@@ -113,7 +79,7 @@ identityProvider = -> ...@@ -113,7 +79,7 @@ identityProvider = ->
request: (options={}) -> request: (options={}) ->
{oncancel} = options {oncancel} = options
result = $injector.invoke(provider.requestAuthentication, provider) result = $injector.invoke(provider.requestAuthentication, provider)
$q.when(result).then(invokeCallbacks, oncancel) $q.when(result).then(onlogin, oncancel)
###* ###*
# @ngdoc method # @ngdoc method
...@@ -122,9 +88,9 @@ identityProvider = -> ...@@ -122,9 +88,9 @@ identityProvider = ->
# https://developer.mozilla.org/en-US/docs/Web/API/navigator.id.watch # https://developer.mozilla.org/en-US/docs/Web/API/navigator.id.watch
### ###
watch: (options) -> watch: (options) ->
{loggedInUser, onlogin, onlogout, onmatch, onready} = options {loggedInUser, onlogin, onlogout, onready} = options
result = $injector.invoke(provider.checkAuthentication, provider) result = $injector.invoke(provider.checkAuthentication, provider)
$q.when(result).then(invokeCallbacks, null, onready) $q.when(result).then(onlogin).finally(-> onready?())
] ]
......
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