├── auth
├── Dockerfile
└── auth_server.py
├── docker-compose.yml
├── cas_redirect.html
└── nginx-site.conf
/auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python
2 | RUN pip install flask
3 | COPY auth_server.py /
4 | ENV FLASK_APP auth_server.py
5 | ENV FLASK_RUN_PORT 80
6 | ENV FLASK_RUN_HOST 0.0.0.0
7 | CMD ["flask", "run"]
8 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | revproxy:
5 | image: nginx
6 | ports:
7 | - 8000:80
8 | volumes:
9 | - ./nginx-site.conf:/etc/nginx/conf.d/default.conf:ro
10 |
11 | auth:
12 | build: auth
13 | environment:
14 | - SECRET_KEY=12345678
15 |
16 | upstream:
17 | image: nginx
18 |
--------------------------------------------------------------------------------
/cas_redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Redirecting...
7 |
8 |
9 | Redirecting...
10 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/nginx-site.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 |
4 | server_name _;
5 |
6 | absolute_redirect off;
7 |
8 | location = /login {
9 | proxy_pass http://auth;
10 | proxy_set_header Host $http_host;
11 | }
12 |
13 | location = /logout {
14 | proxy_pass http://auth;
15 | proxy_set_header Host $http_host;
16 | }
17 |
18 | location = /auth {
19 | internal;
20 | proxy_pass http://auth;
21 | }
22 |
23 | location / {
24 | auth_request /auth;
25 | proxy_pass http://upstream/;
26 | proxy_set_header Host $http_host;
27 | error_page 401 = @error401;
28 | }
29 |
30 | location @error401 {
31 | return 302 /login;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/auth/auth_server.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from urllib.parse import urlencode
3 | from flask import redirect, request, abort, session
4 | from urllib.request import urlopen
5 | from xml.etree import ElementTree
6 | import os
7 | import uuid
8 |
9 |
10 | casURL = "https://passport.ustc.edu.cn/login"
11 | validateURL = "https://passport.ustc.edu.cn/serviceValidate"
12 | redirectURL = "http://home.ustc.edu.cn/~zzh1996/cas_redirect.html"
13 | logoutURL = "https://passport.ustc.edu.cn/logout"
14 |
15 | app = Flask(__name__)
16 | app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
17 |
18 |
19 | def check_ticket(ticket, service):
20 | validate = validateURL + "?" + urlencode({"service": service, "ticket": ticket})
21 | with urlopen(validate) as req:
22 | tree = ElementTree.fromstring(req.read())[0]
23 | cas = "{http://www.yale.edu/tp/cas}"
24 | if tree.tag != cas + "authenticationSuccess":
25 | return None
26 | gid = tree.find("attributes").find(cas + "gid").text.strip()
27 | user = tree.find(cas + "user").text.strip()
28 | return user
29 |
30 |
31 | @app.route("/auth")
32 | def auth():
33 | if "user" in session:
34 | return session["user"]
35 | else:
36 | return abort(401)
37 |
38 |
39 | @app.route("/login")
40 | def login():
41 | if "id" not in session:
42 | session["id"] = uuid.uuid4().hex
43 | jump = request.base_url + "?" + urlencode({"id": session["id"]})
44 | service = redirectURL + "?" + urlencode({"jump": jump})
45 | ticket = request.args.get("ticket")
46 | if not ticket:
47 | return redirect(casURL + "?" + urlencode({"service": service}))
48 | if request.args.get("id") != session["id"]:
49 | abort(401)
50 | user = check_ticket(ticket, service)
51 | if user:
52 | session["user"] = user
53 | return redirect("/")
54 | else:
55 | return abort(401)
56 |
57 |
58 | @app.route("/logout")
59 | def logout():
60 | if "user" in session:
61 | del session["user"]
62 | return redirect(logoutURL)
63 |
--------------------------------------------------------------------------------