Skip to content

Commit 3ec1055

Browse files
authored
Merge pull request #176 from ComputerScienceHouse/develop
Conditional v1.7.0
2 parents bdb6d21 + ac66f9e commit 3ec1055

34 files changed

+689
-665
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: python
22
python:
3-
- "3.3"
3+
- "3.6"
44

55
install:
66
- "pip install -r requirements.txt"

Dockerfile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM python:3.6-stretch
2+
MAINTAINER Devin Matte <matted@csh.rit.edu>
3+
4+
RUN mkdir /opt/conditional
5+
6+
ADD requirements.txt /opt/conditional
7+
8+
WORKDIR /opt/conditional
9+
10+
RUN apt-get -yq update && \
11+
apt-get -yq install libsasl2-dev libldap2-dev libssl-dev && \
12+
pip install -r requirements.txt && \
13+
apt-get -yq clean all
14+
15+
ADD . /opt/conditional
16+
17+
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - && \
18+
apt-get -yq update && \
19+
apt-get -yq install nodejs npm && \
20+
npm install && \
21+
npm run production && \
22+
rm -rf node_modules && \
23+
apt-get -yq remove nodejs npm && \
24+
apt-get -yq clean all
25+
26+
CMD ["gunicorn", "conditional:app", "--bind=0.0.0.0:8080", "--access-logfile=-"]

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,24 @@ Then, install the pipeline and frontend dependencies:
3131
npm install
3232
```
3333

34+
### Config
35+
3436
You must create `config.py` in the top-level directory with the appropriate credentials for the application to run. See `config.sample.py` for an example.
3537

38+
#### Add OIDC Config
39+
Reach out to an RTP to get OIDC credentials that will allow you to develop locally behind OIDC auth
40+
```
41+
# OIDC Config
42+
OIDC_ISSUER = "https://sso.csh.rit.edu/auth/realms/csh"
43+
OIDC_CLIENT_CONFIG = {
44+
'client_id': '',
45+
'client_secret': '',
46+
'post_logout_redirect_uris': ['http://0.0.0.0:6969/logout']
47+
}
48+
```
49+
50+
### Run
51+
3652
Once you have all of the dependencies installed, simply run:
3753

3854
```

conditional/__init__.py

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1+
# pylint: disable=wrong-import-order
2+
from ._version import __version__
3+
14
import os
2-
import subprocess
35
from datetime import datetime
4-
from flask import Flask, redirect, request, render_template, g
5-
from flask_sqlalchemy import SQLAlchemy
6-
from flask_migrate import Migrate
6+
77
from csh_ldap import CSHLDAP
8-
from raven import fetch_git_sha
8+
from flask import Flask, redirect, render_template, g
9+
from flask_migrate import Migrate
10+
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
11+
from flask_sqlalchemy import SQLAlchemy
912
from raven.contrib.flask import Sentry
10-
from raven.exceptions import InvalidGitRepository
1113
import structlog
1214

15+
from conditional import config
16+
1317
app = Flask(__name__)
1418

15-
config = os.path.join(app.config.get('ROOT_DIR', os.getcwd()), "config.py")
19+
app.config.from_object(config)
20+
if os.path.exists(os.path.join(os.getcwd(), "config.py")):
21+
app.config.from_pyfile(os.path.join(os.getcwd(), "config.py"))
1622

17-
app.config.from_pyfile(config)
1823
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
1924

20-
app.config["GIT_REVISION"] = subprocess.check_output(['git',
21-
'rev-parse',
22-
'--short',
23-
'HEAD']).decode('utf-8').rstrip()
24-
25+
app.config["VERSION"] = __version__
2526

2627
db = SQLAlchemy(app)
2728
migrate = Migrate(app, db)
@@ -31,28 +32,38 @@
3132
app.config['LDAP_BIND_PW'],
3233
ro=app.config['LDAP_RO'])
3334

35+
auth = OIDCAuthentication(app, issuer=app.config["OIDC_ISSUER"],
36+
client_registration_info=app.config["OIDC_CLIENT_CONFIG"])
37+
38+
app.secret_key = app.config["SECRET_KEY"]
39+
40+
3441
def start_of_year():
3542
start = datetime(datetime.today().year, 6, 1)
3643
if datetime.today() < start:
37-
start = datetime(datetime.today().year-1, 6, 1)
44+
start = datetime(datetime.today().year - 1, 6, 1)
3845
return start
3946

47+
4048
# pylint: disable=C0413
41-
from conditional.models.models import UserLog
49+
from .models.models import UserLog
50+
4251

4352
# Configure Logging
44-
def request_processor(logger, log_method, event_dict): # pylint: disable=unused-argument, redefined-outer-name
53+
def request_processor(logger, log_method, event_dict): # pylint: disable=unused-argument, redefined-outer-name
4554
if 'request' in event_dict:
4655
flask_request = event_dict['request']
47-
event_dict['user'] = flask_request.headers.get("x-webauth-user")
4856
event_dict['ip'] = flask_request.remote_addr
4957
event_dict['method'] = flask_request.method
5058
event_dict['blueprint'] = flask_request.blueprint
5159
event_dict['path'] = flask_request.full_path
60+
if 'auth_dict' in event_dict:
61+
auth_dict = event_dict['auth_dict']
62+
event_dict['user'] = auth_dict['username']
5263
return event_dict
5364

5465

55-
def database_processor(logger, log_method, event_dict): # pylint: disable=unused-argument, redefined-outer-name
66+
def database_processor(logger, log_method, event_dict): # pylint: disable=unused-argument, redefined-outer-name
5667
if 'request' in event_dict:
5768
if event_dict['method'] != 'GET':
5869
log = UserLog(
@@ -62,35 +73,37 @@ def database_processor(logger, log_method, event_dict): # pylint: disable=unused
6273
blueprint=event_dict['blueprint'],
6374
path=event_dict['path'],
6475
description=event_dict['event']
65-
)
76+
)
6677
db.session.add(log)
6778
db.session.flush()
6879
db.session.commit()
6980
del event_dict['request']
7081
return event_dict
7182

83+
7284
structlog.configure(processors=[
7385
request_processor,
7486
database_processor,
7587
structlog.processors.KeyValueRenderer()
76-
])
88+
])
7789

7890
logger = structlog.get_logger()
7991

80-
81-
from conditional.blueprints.dashboard import dashboard_bp # pylint: disable=ungrouped-imports
82-
from conditional.blueprints.attendance import attendance_bp
83-
from conditional.blueprints.major_project_submission import major_project_bp
84-
from conditional.blueprints.intro_evals import intro_evals_bp
85-
from conditional.blueprints.intro_evals_form import intro_evals_form_bp
86-
from conditional.blueprints.housing import housing_bp
87-
from conditional.blueprints.spring_evals import spring_evals_bp
88-
from conditional.blueprints.conditional import conditionals_bp
89-
from conditional.blueprints.member_management import member_management_bp
90-
from conditional.blueprints.slideshow import slideshow_bp
91-
from conditional.blueprints.cache_management import cache_bp
92-
from conditional.blueprints.co_op import co_op_bp
93-
from conditional.blueprints.logs import log_bp
92+
from conditional.util.auth import get_user
93+
94+
from .blueprints.dashboard import dashboard_bp # pylint: disable=ungrouped-imports
95+
from .blueprints.attendance import attendance_bp
96+
from .blueprints.major_project_submission import major_project_bp
97+
from .blueprints.intro_evals import intro_evals_bp
98+
from .blueprints.intro_evals_form import intro_evals_form_bp
99+
from .blueprints.housing import housing_bp
100+
from .blueprints.spring_evals import spring_evals_bp
101+
from .blueprints.conditional import conditionals_bp
102+
from .blueprints.member_management import member_management_bp
103+
from .blueprints.slideshow import slideshow_bp
104+
from .blueprints.cache_management import cache_bp
105+
from .blueprints.co_op import co_op_bp
106+
from .blueprints.logs import log_bp
94107

95108
app.register_blueprint(dashboard_bp)
96109
app.register_blueprint(attendance_bp)
@@ -106,7 +119,8 @@ def database_processor(logger, log_method, event_dict): # pylint: disable=unused
106119
app.register_blueprint(co_op_bp)
107120
app.register_blueprint(log_bp)
108121

109-
from conditional.util.ldap import ldap_get_member
122+
from .util.ldap import ldap_get_member
123+
110124

111125
@app.route('/<path:path>')
112126
def static_proxy(path):
@@ -115,20 +129,28 @@ def static_proxy(path):
115129

116130

117131
@app.route('/')
132+
@auth.oidc_auth
118133
def default_route():
119134
return redirect('/dashboard')
120135

136+
137+
@app.route("/logout")
138+
@auth.oidc_logout
139+
def logout():
140+
return redirect("/", 302)
141+
142+
121143
@app.errorhandler(404)
122144
@app.errorhandler(500)
123-
def route_errors(error):
145+
@auth.oidc_auth
146+
@get_user
147+
def route_errors(error, user_dict=None):
124148
data = dict()
125-
username = request.headers.get('x-webauth-user')
126149

127150
# Handle the case where the header isn't present
128-
if username is not None:
129-
member = ldap_get_member(username)
130-
data['username'] = member.uid
131-
data['name'] = member.cn
151+
if user_dict['username'] is not None:
152+
data['username'] = user_dict['account'].uid
153+
data['name'] = user_dict['account'].cn
132154
else:
133155
data['username'] = "unknown"
134156
data['name'] = "Unknown"
@@ -149,15 +171,17 @@ def route_errors(error):
149171
error_desc = type(error).__name__
150172

151173
return render_template('errors.html',
152-
error=error_desc,
153-
error_code=code,
154-
event_id=g.sentry_event_id,
155-
public_dsn=sentry.client.get_public_dsn('https'),
156-
**data), int(code)
174+
error=error_desc,
175+
error_code=code,
176+
event_id=g.sentry_event_id,
177+
public_dsn=sentry.client.get_public_dsn('https'),
178+
**data), int(code)
179+
157180

158181
@app.cli.command()
159182
def zoo():
160183
from conditional.models.migrate import free_the_zoo
161184
free_the_zoo(app.config['ZOO_DATABASE_URI'])
162185

186+
163187
logger.info('conditional started')

conditional/_version.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "1.7.0"

0 commit comments

Comments
 (0)