-
Notifications
You must be signed in to change notification settings - Fork 12
/
sax_parser.js
171 lines (163 loc) · 5.55 KB
/
sax_parser.js
1
2
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
var libxmljs = require("libxmljs")
var parseUrl = require('url').parse
var redis = require("redis")
var logger = require('./logger')('cas_validate::sax_parser')
var set_session = require('./ticket_store').set_session
var _ = require('underscore')
function make_sax_parser(req,res,next){
var saxparser = new libxmljs.SaxParser()
var errors
req.session.attributes={}
delete req.session.name
function usercharhandler(chars){
req.session.name = chars
return null
}
function attrcharhandler(attrname){
return function(chars){
req.session.attributes[attrname]=chars
return null
}
}
function attrhandler(e,a,p,u,n){
saxparser.once('characters',attrcharhandler(e))
}
function startHandler(elem, attrs, prefix, uri, namespaces) {
if(elem === 'authenticationSuccess'){
logger.debug('auth passed ');
req.session.st = req.session.ticket;
// stuff into a redis session for single sign off
// set_session(req.session.st,req.sessionID);
set_session(req,function(err){
if(err){
errors = err
return next(err)
}
return null
})
}
if(elem==='authenticationFailure'){
var attr = attrs[0]
if(attr[0]==='code' && attr[3]==='INVALID_TICKET'){
logger.debug('auth failed') ;
delete req.session.st
}
}
if(elem==='user'){
// valid user
saxparser.on('characters',usercharhandler)
}
if(elem==='attributes'){
// valid user
saxparser.on('startElementNS',attrhandler)
}
return null
}
saxparser.on('startElementNS',startHandler)
function endHandler(elem, attrs, prefix, uri, namespaces) {
// could also use once above, but this is safer
if(elem==='user'){
// turn off user chars handler
saxparser.removeListener('characters',usercharhandler)
}
if(elem==='attributes'){
// valid attributes, done
saxparser.removeListener('startElementNS',attrhandler)
}
}
saxparser.on('endElementNS',endHandler)
saxparser.on('endDocument',function(){
// strip the ticket and redirect back
// // this doesn't work properly
// if(url.query.ticket){
// delete url.query.ticket
// delete url.search
// }
//
// the above is okay, but fails because it does nothing.
// redirecting works, but kills the session, so you end up
// in a redirect loop.
//
// no matter what I try, redirect will kill the session.
// so just live with the ticket for now until I figure this out
if(req.session.st){
logger.debug('parsed xml doc, got: user name = '+req.session.name+', attributes are: ' +JSON.stringify(req.session.attributes))
if(!errors){
next()
}
}else{
// possibly a bad, stale ticket in request
var url = parseUrl(req.url,true);
var path = url.pathname
res.writeHead(307, { 'location': path })
res.end()
}
return null
})
return saxparser
}
/**
* get_username
*
* get the user name provided by the CAS server, stored in the current session
*
* You can also directly access them at req.session.name, but
* just in case that changes you can always rely on this to do the
* right thing
*
* will invoke the callback with (error,{'username':username})
*
* If there is no username (perhaps you do not have a CAS session),
* then it will invoke callback with (error,{}) (an empty object)
*
* @param {Object} req the http.IncomingMessage (from express or connect)
* @param {Function} next the callback to invoke with the username object
* @return {Object} returns whatever next invocation returns
* @api public
*
*/
function get_username(req,next){
if(req.session !== undefined && req.session.name !== undefined){
return next(null,{'user_name':req.session.name})
}else{
return next(null,{})
}
}
/**
* get_attributes
*
* get the user attributes parsed by xml parser and stored in the
* session. Also, get the username too while we're at it.
*
* You can also directly access them at req.session.attributes, but
* just in case that changes you can always rely on this to do the
* right thing
*
* will invoke the callback with (error,attributes) attributes will
* include username as well. see the documentation above for
* get_username
*
* if there are not attributes, will return only the username object
*
* If the attributes are empty and there is no username (perhaps there
* is not a CAS session for this user), will invoke callback with
* (error,{}) (an empty object)
*
* @param {Object} req the http.IncomingMessage (from express or connect)
* @param {Function} next the callback to invoke with the attributes
* @return {Object} returns whatever next invocation returns
* @api public
*
*/
function get_attributes(req,next){
return get_username(req,function(err,obj){
if(req.session !== undefined && req.session.attributes !== undefined){
return next(null,_.extend(obj,req.session.attributes))
}else{
return next(null,obj)
}
})
}
exports.make_sax_parser=make_sax_parser
exports.get_username=get_username
exports.get_attributes=get_attributes