Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/scripts/auth/gen-sso.py
Views: 286
1
#!/usr/bin/env python3
2
3
# This is 100% for development only. None of these configurations are real!
4
# This is a quick and simple script to generate PostgreSQL commands to re-create the passport_strategy table.
5
# As a first command, it deletes everything you have there -- hence this is 100% only for development!
6
# Usage:
7
# python3 cocalc-db-sso.py [dump]
8
# which issues commands to psql directly, or add "dump" to see what it would do.
9
#
10
# The conf/info fields are described in src/packages/server/auth/sso/types.ts
11
12
from typing_extensions import TypedDict
13
from typing import Dict
14
15
Entry = TypedDict("Entry", {"strategy": str, "conf": Dict, "info": Dict})
16
17
# the first 4 ones have no functional purpose – good for checking the UI, etc.
18
19
food: Entry = {
20
"strategy": "food",
21
"conf": {
22
"icon": "https://img.icons8.com/glyph-neue/344/food-and-wine.png",
23
"type": "oauth2next",
24
"scope": ["email", "profile"],
25
"display": "Food University",
26
"clientID": "CoCalc_Client",
27
"tokenURL": "https://localhost/oauth2/wowtech/access_token",
28
"login_info": {
29
"emails": "emails[0].value"
30
},
31
"userinfoURL": "https://localhost/oauth2/userinfo",
32
"clientSecret": "sEcRet1234",
33
"authorizationURL": "https://localhost/oauth2/authorize"
34
},
35
"info": {
36
"public": False,
37
"description":
38
"This is the SSO mechanism for anyone associated with Food University",
39
"exclusive_domains": ["food.edu"]
40
}
41
}
42
43
flight: Entry = {
44
"strategy": "flight",
45
"conf": {
46
"type": "oauth2next",
47
"scope": ["email", "profile"],
48
"clientID": "CoCalc_Client",
49
"tokenURL": "https://localhost/oauth2/wowtech/access_token",
50
"login_info": {
51
"emails": "emails[0].value"
52
},
53
"userinfoURL": "https://localhost/oauth2/userinfo",
54
"clientSecret": "sEcRet1234",
55
"authorizationURL": "https://localhost/oauth2/authorize"
56
},
57
"info": {
58
"icon":
59
"https://img.icons8.com/external-kiranshastry-solid-kiranshastry/344/external-flight-interface-kiranshastry-solid-kiranshastry.png",
60
"public": False,
61
"display": "Flight Research",
62
"description":
63
"This is to sign up with CoCalc as a student of **Flight Research International, Inc.**\n\nMore information:\n\n- [airplane.edu](http://airplane.edu/)\n\n- [yet another link](http://nowhere.com)",
64
"exclusive_domains": ["airplane.edu", "aircraft.com"]
65
}
66
}
67
68
minimal: Entry = {
69
"strategy": "minimal",
70
"conf": {
71
"type": "oauth2next",
72
"display": "Minimal",
73
"clientID": "CoCalc_Client",
74
"tokenURL": "https://localhost/oauth2/wowtech/access_token",
75
"login_info": {
76
"emails": "emails[0].value"
77
},
78
"userinfoURL": "https://localhost/oauth2/userinfo",
79
"clientSecret": "sEcRet1234",
80
"authorizationURL": "https://localhost/oauth2/authorize"
81
},
82
"info": {
83
"public": False,
84
"do_not_hide": True,
85
"exclusive_domains": ["minimal.edu"]
86
}
87
}
88
89
abacus2: Entry = {
90
"strategy": "abacus2",
91
"conf": {
92
"type": "oauth2next",
93
"scope": ["email", "profile"],
94
"clientID": "CoCalc_Client",
95
"tokenURL": "https://localhost/oauth2/wowtech/access_token",
96
"login_info": {
97
"emails": "emails[0].value"
98
},
99
"userinfoURL": "https://localhost/oauth2/userinfo",
100
"clientSecret": "sEcRet1234",
101
"authorizationURL": "https://localhost/oauth2/authorize"
102
},
103
"info": {
104
"icon":
105
"https://img.icons8.com/external-smashingstocks-outline-color-smashing-stocks/344/external-abacus-online-education-smashingstocks-outline-color-smashing-stocks.png",
106
"public":
107
False,
108
"display":
109
"Abacus 2",
110
"description":
111
"This is the SSO mechanism for anyone associated with Abacus Inc",
112
"exclusive_domains":
113
["abacus.edu", "dadacus.edu", "nadacus.edu", "blablacus.edu"]
114
}
115
}
116
117
oidc1: Entry = {
118
"strategy": "oidc1",
119
"conf": {
120
"type": "oidc",
121
"issuer": "http://localhost:5300",
122
"authorizationURL": "http://localhost:5300/auth",
123
"tokenURL": "http://localhost:5300/token",
124
"userInfoURL": "http://localhost:5300/me",
125
"clientID": "cocalc",
126
"clientSecret": "s3cr3t",
127
"callbackURL": "http://localhost:5000/auth/oidc1/return",
128
},
129
"info": {
130
"display": "OIDC Test",
131
"description":
132
"This is the SSO mechanism for anyone associated with OIDC Test",
133
"public": False,
134
}
135
}
136
137
strats = [food, flight, minimal, abacus2, oidc1]
138
139
# read content of file saml-idp-local.pem
140
# curdir is the directory of this file
141
from os.path import join, dirname, realpath, exists, abspath
142
143
curdir = dirname(realpath(__file__))
144
saml20fn = join(curdir, "saml-idp-local.pem")
145
146
if exists(saml20fn):
147
print("Generating SAML 2.0 SSO strategy")
148
saml20cert: str = open(saml20fn, "r").read()
149
saml20: Entry = {
150
"strategy": "saml20",
151
"conf": {
152
"type": "saml",
153
"name": "saml20",
154
"entryPoint": "http://localhost:7000/saml/sso",
155
"path": "/auth/saml20/return",
156
#"audience": False, # "https://localhost:5000/", # false is set as default
157
"login_info": {
158
"first_name": "firstName",
159
"last_name": "lastName",
160
"full_name": "displayName",
161
"emails": "email",
162
"id": "email",
163
},
164
"issuer": "https://cocalc.com",
165
"cert": saml20cert
166
},
167
"info": {
168
"icon":
169
"https://b.thumbs.redditmedia.com/EQ1HS4MFeamF4Yw6ufKYWkSkmcsikv4VvQ4dYzfsmGw.png",
170
"public": False,
171
"display": "Saml20",
172
"description": "Testing my SAML 2.0 IdP",
173
"exclusive_domains": ["example.com"],
174
"update_on_login": True,
175
"cookie_ttl_s": 24 * 60 * 60, # 24 hours
176
}
177
}
178
strats.append(saml20)
179
else:
180
print(
181
f"WARNING: no SAML 2.0 generated. Setup saml-idp and copy the pem file certificate to exactly {saml20fn}"
182
)
183
184
# Setting up a test OAuth2 server is hard, or I don't know how to do it.
185
# In any case, this test was using gerges-beshay/oauth2orize-examples
186
# with small modifications: db/users has a given_name and family_name,
187
# and routes/user returns them in the json response.
188
# $ PORT=5555 node app.js
189
oauth2server = 'http://localhost:5555'
190
oauth2: Entry = {
191
"strategy": "myOauth2",
192
"conf": {
193
"type": "oauth2",
194
"scope": ["email", "profile"],
195
"authorizationURL": f'{oauth2server}/dialog/authorize',
196
"tokenURL": f'{oauth2server}/oauth/token',
197
"userinfoURL": f'{oauth2server}/api/userinfo',
198
"clientID": 'abc123',
199
"clientSecret": 'ssh-secret',
200
#"login_info": {
201
# "id": "_raw.user_id",
202
#}
203
},
204
"info": {
205
"public": False,
206
"display": "My OAuth2",
207
"description": "My OAuth2",
208
"update_on_login": False,
209
}
210
}
211
strats.append(oauth2)
212
213
# fake public
214
215
twitter: Entry = {
216
"strategy": "twitter",
217
"conf": {
218
"clientID": "123",
219
"clientSecret": "123123"
220
},
221
}
222
strats.append(twitter)
223
224
github: Entry = {
225
"strategy": "github",
226
"conf": {
227
"clientID": "123",
228
"clientSecret": "123123"
229
},
230
}
231
strats.append(github)
232
233
##############
234
235
sql_commands = []
236
237
from json import dumps
238
239
sql_commands.append("DELETE FROM passport_settings;")
240
241
insertPattern = "INSERT INTO passport_settings (strategy, conf, info) VALUES ('{strategy}', '{conf}'::JSONB, '{info}'::JSONB);"
242
243
for strat in strats:
244
print("Inserting", strat["strategy"])
245
sql_commands.append(
246
insertPattern.format(strategy=strat["strategy"],
247
conf=dumps(strat["conf"]),
248
info=dumps(strat.get("info"))))
249
250
import sys
251
if len(sys.argv) > 1 and sys.argv[1] == 'dump':
252
print()
253
print('commands:')
254
print()
255
for sql in sql_commands:
256
print(sql)
257
exit()
258
259
from subprocess import run
260
261
# this needs all env variables to set properly, e.g. source an "postgres-env" file first
262
run(["psql"], check=True, input="\n".join(sql_commands).encode('utf8'))
263
264