├── 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 | --------------------------------------------------------------------------------