Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/scripts/auth/gen-sso.py
1381 views
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().strip()
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
# "_sep": "->", # uncomment this to test _sep, no need to change the values above
164
},
165
"issuer": "https://cocalc.com",
166
"cert": saml20cert
167
},
168
"info": {
169
"icon":
170
"https://b.thumbs.redditmedia.com/EQ1HS4MFeamF4Yw6ufKYWkSkmcsikv4VvQ4dYzfsmGw.png",
171
"public": False,
172
"display": "Saml20",
173
"description": "Testing my SAML 2.0 IdP",
174
"exclusive_domains": ["example.com"],
175
"update_on_login": True,
176
"cookie_ttl_s": 24 * 60 * 60, # 24 hours
177
}
178
}
179
strats.append(saml20)
180
else:
181
print(
182
f"WARNING: no SAML 2.0 generated. Setup saml-idp and copy the pem file certificate to exactly {saml20fn}"
183
)
184
185
# Setting up a test OAuth2 server is hard, or I don't know how to do it.
186
# In any case, this test was using gerges-beshay/oauth2orize-examples
187
# with small modifications: db/users has a given_name and family_name,
188
# and routes/user returns them in the json response.
189
# $ PORT=5555 node app.js
190
oauth2server = 'http://localhost:5555'
191
oauth2: Entry = {
192
"strategy": "myOauth2",
193
"conf": {
194
"type": "oauth2",
195
"scope": ["email", "profile"],
196
"authorizationURL": f'{oauth2server}/dialog/authorize',
197
"tokenURL": f'{oauth2server}/oauth/token',
198
"userinfoURL": f'{oauth2server}/api/userinfo',
199
"clientID": 'abc123',
200
"clientSecret": 'ssh-secret',
201
#"login_info": {
202
# "id": "_raw.user_id",
203
#}
204
},
205
"info": {
206
"public": False,
207
"display": "My OAuth2",
208
"description": "My OAuth2",
209
"update_on_login": False,
210
}
211
}
212
strats.append(oauth2)
213
214
# fake public
215
216
twitter: Entry = {
217
"strategy": "twitter",
218
"conf": {
219
"clientID": "123",
220
"clientSecret": "123123"
221
},
222
}
223
strats.append(twitter)
224
225
github: Entry = {
226
"strategy": "github",
227
"conf": {
228
"clientID": "123",
229
"clientSecret": "123123"
230
},
231
}
232
strats.append(github)
233
234
##############
235
236
sql_commands = []
237
238
from json import dumps
239
240
sql_commands.append("DELETE FROM passport_settings;")
241
242
insertPattern = "INSERT INTO passport_settings (strategy, conf, info) VALUES ('{strategy}', '{conf}'::JSONB, '{info}'::JSONB);"
243
244
for strat in strats:
245
print("Inserting", strat["strategy"])
246
sql_commands.append(
247
insertPattern.format(strategy=strat["strategy"],
248
conf=dumps(strat["conf"]),
249
info=dumps(strat.get("info"))))
250
251
import sys
252
if len(sys.argv) > 1 and sys.argv[1] == 'dump':
253
print()
254
print('commands:')
255
print()
256
for sql in sql_commands:
257
print(sql)
258
exit()
259
260
from subprocess import run
261
262
# this needs all env variables to set properly, e.g. source an "postgres-env" file first
263
run(["psql"], check=True, input="\n".join(sql_commands).encode('utf8'))
264
265