forked from atoy40/meteor-accounts-cas
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cas_server.js
115 lines (93 loc) · 3.26 KB
/
cas_server.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
var Future = Npm.require('fibers/future');
var url = Npm.require('url');
var CAS = Npm.require('cas');
var _casCredentialTokens = {};
function log(message) {
console.log(["[accounts-cas]", message].join(" "));
}
if (Meteor.settings.cas && !!Meteor.settings.cas.relaxSSL) {
log("** DISABLING SSL CERTIFICATE VERIFICATION **");
// SSL certificate verification can be disabled for dev environments
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
var casTicket = function (ticket, token, site) {
check(ticket, String);
check(token, String);
check(site, String);
var fut = new Future();
// get configuration
if (!Meteor.settings.public || !Meteor.settings.public.cas) {
log("unable to get configuration");
return;
}
var casSiteID = Meteor.settings.public.cas.namespace ? Meteor.settings.public.cas.namespace + "$" + site : site;
var cas = new CAS({
base_url: [Meteor.settings.public.cas.baseUrl, casSiteID].join("/"),
service: [Meteor.absoluteUrl().replace(/\/+$/, ""), "cas", site, token].join("/")
});
cas.validate(ticket, function(err, status, username) {
if (err) {
log("error when trying to validate " + err);
} else {
if (status) {
var siteUser = [username, site].join("@");
log("user validated " + siteUser);
_casCredentialTokens[token] = { id: siteUser };
} else {
log("unable to validate " + ticket);
}
}
fut.return("done");
});
fut.wait();
return;
};
/*
* Register a server-side login handle.
* It is call after Accounts.callLoginMethod() is call from client.
*
*/
Accounts.registerLoginHandler(function (options) {
if (!options.cas)
return undefined;
casTicket(options.cas.ticket, options.cas.credentialToken, options.cas.site);
if (!_hasCredential(options.cas.credentialToken)) {
throw new Meteor.Error(Accounts.LoginCancelledError.numericError,
'no matching login attempt found');
}
var result = _retrieveCredential(options.cas.credentialToken);
var data = { profile: { name: result.id } };
var output = Accounts.updateOrCreateUserFromExternalService("cas", result, data);
if (Partitioner && "function" === typeof Partitioner.directOperation) {
Partitioner.directOperation(function() {
var userId = output.userId, site = options.cas.site;
var user = Meteor.users.findOne(userId);
var ownedByTenant = Partitioner.getUserGroup(userId);
if (!user.admin) {
if (!ownedByTenant) {
Partitioner.setUserGroup(userId, site);
ownedByTenant = site;
}
if (!user.group) {
Meteor.users.update({_id: userId}, {$set: {group: ownedByTenant}});
user = Meteor.users.findOne(userId);
}
if (site !== ownedByTenant || site !== user.group) {
throw new Meteor.Error(Accounts.LoginCancelledError.numericError, "User is not part of site: " + options.cas.site);
}
}
});
}
return output;
});
var _hasCredential = function(credentialToken) {
return _.has(_casCredentialTokens, credentialToken);
};
/*
* Retrieve token and delete it to avoid replaying it.
*/
var _retrieveCredential = function(credentialToken) {
var result = _casCredentialTokens[credentialToken];
delete _casCredentialTokens[credentialToken];
return result;
};