u2f.coffee 9.62 KB
Newer Older
1
###
2
# Session explorer
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
###

# Max number of session to display (see overScheme)
max = 25

# Queries to do each type of display: each array item corresponds to the depth
# of opened nodes in the tree
schemes =
	_whatToTrace: [
		(t,v) ->
			"groupBy=substr(#{t},1)"
		(t,v) ->
			"#{t}=#{v}*&groupBy=#{t}"
		(t,v) ->
			"#{t}=#{v}"
	]
	ipAddr: [
		(t,v) ->
			"groupBy=net(#{t},16,1)"
		(t,v) ->
			v = v + '.' unless v.match /:/
			"#{t}=#{v}*&groupBy=net(#{t},32,2)"
		(t,v) ->
			v = v + '.' unless v.match /:/
			"#{t}=#{v}*&groupBy=net(#{t},48,3)"
		(t,v) ->
			v = v + '.' unless v.match /:/
			"#{t}=#{v}*&groupBy=net(#{t},128,4)"
		(t,v) ->
			"#{t}=#{v}&groupBy=_whatToTrace"
		(t,v,q) ->
			q.replace(/\&groupBy.*$/, '') + "&_whatToTrace=#{v}"
	]
	_startTime: [
		(t,v) ->
			"groupBy=substr(#{t},8)"
		(t,v) ->
			"#{t}=#{v}*&groupBy=substr(#{t},10)"
		(t,v) ->
			"#{t}=#{v}*&groupBy=substr(#{t},11)"
		(t,v) ->
			"#{t}=#{v}*&groupBy=substr(#{t},12)"
		(t,v) ->
			"#{t}=#{v}*&groupBy=_whatToTrace"
		(t,v,q) ->
			console.log t
			console.log v
			console.log q
			q.replace(/\&groupBy.*$/, '') + "&_whatToTrace=#{v}"
	]
	doubleIp: [
		(t,v) ->
			t
		(t,v) ->
			"_whatToTrace=#{v}&groupBy=ipAddr"
		(t,v,q) ->
			q.replace(/\&groupBy.*$/, '') + "&ipAddr=#{v}"
	]

overScheme =
	_whatToTrace: (t,v,level,over) ->
		if level == 1
			"#{t}=#{v}*&groupBy=substr(#{t},#{(level+over+1)})"
		else
			null
	ipAddr: (t,v,level,over) ->
		if level > 0 and level < 4
			"#{t}=#{v}*&groupBy=net(#{t},#{16*level+4*(over+1)},2)"
		else
			null

hiddenAttributes = '_password'

# Attributes to group in session display
categories =
    dateTitle:          ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen']
    connectionTitle:    ['ipAddr', '_timezone', '_url']
    authenticationTitle:['_session_id', '_user', '_password', 'authenticationLevel']
    modulesTitle:       ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti']
    saml:               ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump']
    groups:             ['groups', 'hGroups']
    ldap:               ['dn']
    BrowserID:          ['_browserIdAnswer', '_browserIdAnswerRaw']
    OpenIDConnect:      ['_oidc_id_token', '_oidc_OP', '_oidc_access_token']

# Menu entries
menu =
	session: [
		title: 'deleteU2FKey'
		icon:  'trash'
	]
	home: []

###
# AngularJS application
###
llapp = angular.module 'llngSessionsExplorer', ['ui.tree', 'ui.bootstrap', 'llApp']

# Main controller
llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', '$q', '$http', ($scope, $translator, $location, $q, $http) ->
	$scope.links = links
	$scope.menulinks = menulinks
	$scope.staticPrefix = staticPrefix
	$scope.scriptname = scriptname
	$scope.formPrefix = formPrefix
	$scope.availableLanguages = availableLanguages
	$scope.waiting = true
	$scope.showM = false
	$scope.showT = true
	$scope.data = []
	$scope.currentScope = null
	$scope.currentSession = null
	$scope.menu = menu

	# Import translations functions
	$scope.translateP = $translator.translateP
	$scope.translate = $translator.translate
	$scope.translateTitle = (node) ->
		$translator.translateField node, 'title'
122
	sessionType = 'global'
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

	# Handle menu items
	$scope.menuClick = (button) ->
		if button.popup
			window.open button.popup
		else
			button.action = button.title unless button.action
			switch typeof button.action
				when 'function'
					button.action $scope.currentNode, $scope
				when 'string'
					$scope[button.action]()
				else
					console.log typeof button.action
		$scope.showM = false

	# SESSION MANAGEMENT

141
	# Delete U2F key attributs
142 143
	$scope.deleteU2FKey = ->
		$scope.waiting = true
144
		$http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
145
			$scope.currentSession = null
146
			#$scope.currentScope.remove()
147 148
			$scope.waiting = false
		, (resp) ->
149
			$scope.currentSession = null
150
			#$scope.currentScope.remove()
151
			$scope.waiting = false
152
		$scope.showT = true
Yadd's avatar
Tidy  
Yadd committed
153

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
	# Open node
	$scope.stoggle = (scope) ->
		node = scope.$modelValue
		if node.nodes.length == 0
			$scope.updateTree node.value, node.nodes, node.level, node.over, node.query, node.count
		scope.toggle()

	# Display selected session
	$scope.displaySession = (scope) ->

		# Private functions

		# Session preparation
		transformSession = (session) ->
			_stToStr = (s) ->
				s
			_insert = (re, title) ->
				tmp = []
				reg = new RegExp(re)
				for key,value of session
					if key.match(reg) and value
						tmp.push
							title: key
							value: value
						delete session[key]
				if tmp.length > 0
					res.push
						title: title
						nodes: tmp
			time = session._utime
			id = session._session_id

			# 1. Replace values if needed
			for key, value of session
				unless value
					delete session[key]
				else
					if typeof session == 'string' and value.match(/; /)
						session[key] = value.split '; '
					if typeof session[key] != 'object'
						if hiddenAttributes.match(new RegExp('\b' + key + '\b'))
							session[key] = '********'
						else if key.match /^(_utime|_lastAuthnUTime|_lastSeen|notification)$/
							session[key] = $scope.localeDate value
						else if key.match /^(_startTime|_updateTime)$/
							session[key] = _stToStr value
			res = []

202
			# 2. Push session keys in result, grouped by categories
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
			for category, attrs of categories
				subres = []
				for attr in attrs
					if session[attr]
						subres.push
							title: attr
							value: session[attr]
						delete session[attr]
				if subres.length >0
					res.push
						title: "__#{category}__"
						nodes: subres

			# 3. Add OpenID and notifications already notified
			_insert '^openid', 'OpenID'
			_insert '^notification_(.+)', '__notificationsDone__'

			# 4. Add session history if exists
			if session._loginHistory
				tmp = []
				if session._loginHistory.successLogin
					for l in session._loginHistory.successLogin
						tmp.push
							t: l._utime
							title: $scope.localeDate l._utime
							value: "Success (IP #{l.ipAddr})"
				if session._loginHistory.failedLogin
					for l in session._loginHistory.failedLogin
						tmp.push
							t: l._utime
							title: $scope.localeDate l._utime
							value: "#{l.error} (IP #{l.ipAddr})"
				delete session._loginHistory
				tmp.sort (a,b) ->
					a.t - b.t
				res.push
					title: '__loginHistory__'
					nodes: tmp

			# 5. Other keys (attributes and macros)
			tmp = []
			for key, value of session
				tmp.push
					title: key
					value: value
			tmp.sort (a,b) ->
				if a.title > b.title then 1
				else if a.title < b.title then -1
				else 0

			res.push
				title: '__attributesAndMacros__'
				nodes: tmp
			return {
				_utime: time
				id: id
				nodes: res
			}

		$scope.currentScope = scope
		sessionId = scope.$modelValue.session
		$http.get("#{scriptname}sessions/#{sessionType}/#{sessionId}").then (response) ->
			$scope.currentSession = transformSession response.data
		$scope.showT = false

	$scope.localeDate = (s) ->
		d = new Date(s * 1000)
		return d.toLocaleString()

	# Function to change interface language
	$scope.getLanguage = (lang) ->
		$scope.lang = lang
		$scope.form = 'white'
		$scope.init()
		$scope.showM = false

	# URI local path management
	pathEvent = (event, next, current) ->
		n = next.match /#\/(\w+)/
		sessionType = 'global'
		if n == null
			$scope.type = '_whatToTrace'
		else if n[1].match /^(persistent)$/
			sessionType = RegExp.$1
			$scope.type = '_session_uid'
		else
			$scope.type = n[1]
		$scope.init()

	$scope.$on '$locationChangeSuccess', pathEvent

	# Function to update tree: download value of opened subkey
	autoId = 0
	$scope.updateTree = (value, node, level, over, currentQuery, count) ->
		$scope.waiting = true

		# Query scheme selection:

		#  - if defined above
		scheme = if schemes[$scope.type]
			schemes[$scope.type]

		#  - _updateTime must be displayed as startDate
		else if $scope.type == '_updateTime'
			schemes._startTime

		#  - default to _whatToTrace scheme
		else
			schemes._whatToTrace

		# Build query using schemes
		query = scheme[level] $scope.type, value, currentQuery

		# If number of session exceeds "max" and overScheme exists, call it
		if count > max and overScheme[$scope.type]
			if tmp = overScheme[$scope.type] $scope.type, value, level, over, currentQuery
				over++
				query = tmp
				level = level - 1
			else
				over = 0
		else
			over = 0

		# Launch HTTP query
		$http.get("#{scriptname}sessions/#{sessionType}?#{query}").then (response) ->
			data = response.data
			if data.result
				for n in data.values
					autoId++
					n.id = "node#{autoId}"
					if level < scheme.length - 1
						n.nodes = []
						n.level = level + 1
						n.query = query
						n.over  = over

						# Date display in tree
						if $scope.type.match /^(?:start|update)Time$/
							n.title = n.value
							# 12 digits -> 12:34
							.replace(/^(\d{8})(\d{2})(\d{2})$/,'$2:$3')
							# 11 digits -> 12:30
							.replace(/^(\d{8})(\d{2})(\d)$/,'$2:$30')
							# 10 digits -> 12h
							.replace(/^(\d{8})(\d{2})$/,'$2h')
							#  8 digits -> 2016-03-15
							.replace(/^(\d{4})(\d{2})(\d{2})/,'$1-$2-$3')
					node.push n
				$scope.total = data.total if value == ''
			$scope.waiting = false
		, (resp) ->
			$scope.waiting = false

	# Intialization function
	# Simply set $scope.waiting to false during $translator and tree root
	# initialization
	$scope.init = ->
		$scope.waiting = true
		$scope.data = []
		$q.all [
			$translator.init $scope.lang
			$scope.updateTree '', $scope.data, 0, 0
		]
		.then ->
			$scope.waiting = false
		, (resp) ->
			$scope.waiting = false

	# Query scheme initialization
	# Default to '_whatToTrace'
	c = $location.path().match /^\/(\w+)/
	$scope.type = if c then c[1] else '_whatToTrace'
]