Compare commits
No commits in common. "secret" and "docs" have entirely different histories.
8
.gitignore
vendored
@ -1,2 +1,8 @@
|
||||
# ignore mkdocs
|
||||
# ignore mkdocs output/gh-pages branch
|
||||
site/
|
||||
|
||||
# ignore secret branch
|
||||
secret/
|
||||
|
||||
# ignore any makefiles
|
||||
Makefile
|
||||
|
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 458.835.16.92, May 2018
|
||||
|
||||
Copyright (C) 2018 Charles Reid <charles@charlesreid1.com>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
58
README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# github-heroku-attack-rabbits
|
||||
|
||||
## What's this business all about, then?
|
||||
|
||||
This repository helps you protect your secret pages by (deep breath):
|
||||
|
||||
hosting your secret page of static and/or dynamic content using a free Heroku app
|
||||
running a Python Flask server that uses Flask-Dance to authenticate visitors
|
||||
with Github which allows you fine-grained access control over your pages based on
|
||||
user attributes like organization or team membership or even things like how many
|
||||
repositories a user has or how many vowels are in their username.
|
||||
|
||||
Also, did I mention the attack rabbits?
|
||||
|
||||

|
||||
|
||||
|
||||
## Where is everything?
|
||||
|
||||
Final pages:
|
||||
|
||||
* The finished product (pages on Heroku protected by attack rabbits)
|
||||
is at [github-heroku-attack-rabbits.herokuapp.com](https://github-heroku-attack-rabbits.herokuapp.com)
|
||||
|
||||
* The documentation is at [pages.charlesreid1.com/github-heroku-attack-rabbits](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
|
||||
|
||||
Two branches in this repo compose the github-heroku-attack-rabbits documentation:
|
||||
|
||||
* (**YOU ARE HERE**) The [docs](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs) branch
|
||||
contains the files needed to generate the
|
||||
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
|
||||
|
||||
* The [gh-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/gh-pages) branch
|
||||
contains the static files generated from the documentation.
|
||||
The contents of this branch compose the
|
||||
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
|
||||
|
||||
Two branches illustrate github-heroku-attack-rabbits in practice:
|
||||
|
||||
* The [secret](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/secret) branch contains the files needed to create the secret page.
|
||||
This repository is public, so obviously these aren't *actually* secret,
|
||||
but in practice this would be in a protected repository.
|
||||
|
||||
* The [heroku-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/heroku-pages) branch
|
||||
contains the content that is actually pushed to Heroku - that is,
|
||||
the final Flask app.
|
||||
|
||||
|
||||
## Where do I start?
|
||||
|
||||
See the [documentation](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
|
||||
or [docs/index.md](docs/index.md).
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This is released under the [WTFPL](LICENSE).
|
||||
|
16
Readme.md
@ -1,16 +0,0 @@
|
||||
# github-heroku-attack-rabbits: secret branch
|
||||
|
||||
The secret branch contains the mkdocs source files
|
||||
needed to generate the final static content for the
|
||||
secret site.
|
||||
|
||||
The `secret` branch contains the source files,
|
||||
the `heroku-pages` branch contains the finished product.
|
||||
|
||||
The `heroku-pages` branch contains the site that is
|
||||
actually deployed to Heroku at the Github-Heroku attack
|
||||
sheep app:
|
||||
|
||||
* [https://github-heroku-attack-rabbits.herokuapp.com](https://github-heroku-attack-rabbits.herokuapp.com).
|
||||
|
||||
Lost? Visit the [docs](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits) branch.
|
10
docs/css/custom.css
Normal file
@ -0,0 +1,10 @@
|
||||
body {
|
||||
background-color: #efefef;
|
||||
}
|
||||
div.body {
|
||||
background-color: #efefef;
|
||||
}
|
||||
.md-typeset pre {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
33
docs/custom_domains.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Custom Domains
|
||||
|
||||
If you want to use a custom domain:
|
||||
|
||||
* Set up custom domain using Heroku command line interface
|
||||
* This will set up a DNS subdomain specifically for your app
|
||||
* Point your DNS records to the Heroku DNS subdomain
|
||||
|
||||
This also introduces complications with HTTP vs HTTPS:
|
||||
OAuth must happen over HTTPS (required by protocol).
|
||||
But you the user can control your domain and create
|
||||
SSL certificates for it, but Heroku is hosting the app.
|
||||
|
||||
You have two options: the free option, and the pay option.
|
||||
|
||||
**The pay option:** For $7/mo you can upgrade to hobby nodes,
|
||||
which allows you to give Heroku permission to create an SSL
|
||||
certificate for your domain. This is the easiest solution
|
||||
and requires zero setup, zero certificate management.
|
||||
|
||||
**The free option:** You can have your domain (HTTP only)
|
||||
forward to Heroku (HTTPS can't be forwarded - that's ***key***).
|
||||
When you hit the Heroku domain, it will log the user in to Github.
|
||||
When the user logs in successfully, Github will redirect them to
|
||||
the callback URL. This callback URL ***MUST*** be HTTPS, so it cannot
|
||||
redirect back to your (HTTP-only) custom domain.
|
||||
|
||||
That means the userr will, after authenticating with Github,
|
||||
always be redirected to `https://my-cool-app.herokuapp.com`
|
||||
and never `http://my-cool-custom-domain-that-cannot-be-used-as-a-callback-because-it-is-https-only.com`.
|
||||
|
||||
The paid option is much, much simpler in the end
|
||||
and will save you $7/mo in setup time alone.
|
174
docs/flask.md
Normal file
@ -0,0 +1,174 @@
|
||||
# Create a Flask App using Flask-Dance
|
||||
|
||||
This is the heart of the method.
|
||||
|
||||
The best thing to do here is just to walk you through the script.
|
||||
|
||||
Import statements:
|
||||
|
||||
```
|
||||
import os, json
|
||||
from os.path import join, isfile, isdir
|
||||
from werkzeug.contrib.fixers import ProxyFix
|
||||
from flask import Flask, redirect, url_for, send_from_directory
|
||||
from flask_dance.contrib.github import make_github_blueprint, github
|
||||
```
|
||||
|
||||
Note that flask-dance adds an OAuth login/callback route
|
||||
to your Flask app by creating a `/login` blueprint,
|
||||
meaning all the OAuth stuff is just magically available
|
||||
via `/login`.
|
||||
|
||||
Set paths for static content:
|
||||
|
||||
```
|
||||
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
|
||||
STATIC_PATH = 'content'
|
||||
```
|
||||
|
||||
Create and configure app. This requires confidential information
|
||||
for the Github application you created, specifically the client
|
||||
ID and client secret. These are at the very top of the page when
|
||||
you visit your app's settings page.
|
||||
|
||||
To find this, after you log in, click your profile photo in the
|
||||
upper right > Settings > Developer Settings > OAuth Apps > click the
|
||||
name for your OAuth app.
|
||||
|
||||
```
|
||||
app = Flask(__name__)
|
||||
|
||||
# this worked locally, but not on heroku
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app)
|
||||
|
||||
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "9502861d41e8729c5cae3225920b1b46")
|
||||
|
||||
app.config["RESULT_STATIC_PATH"] = STATIC_PATH #os.path.join(PROJECT_ROOT,STATIC_PATH)
|
||||
app.config["GITHUB_OAUTH_CLIENT_ID"] = os.environ.get("GITHUB_OAUTH_CLIENT_ID")
|
||||
app.config["GITHUB_OAUTH_CLIENT_SECRET"] = os.environ.get("GITHUB_OAUTH_CLIENT_SECRET")
|
||||
```
|
||||
|
||||
Now the magic happens: we use flask-dance to create a blueprint
|
||||
that has methods and settings all ready to go for us to do the
|
||||
OAuth dance.
|
||||
|
||||
`make_github_blueprint()` is part of the contrib module of flask-dance.
|
||||
There are several similar methods to generate blueprints for
|
||||
authenticating with other APIs.
|
||||
|
||||
```
|
||||
github_bp = make_github_blueprint(
|
||||
client_id = os.environ.get('GITHUB_OAUTH_CLIENT_ID'),
|
||||
client_secret = os.environ.get('GITHUB_OAUTH_CLIENT_SECRET'),
|
||||
scope='read:org')
|
||||
|
||||
app.register_blueprint(github_bp, url_prefix="/login")
|
||||
|
||||
contents404 = "<html><body><h1>Status: Error 404 Page Not Found</h1></body></html>"
|
||||
contents403 = "<html><body><h1>Status: Error 403 Access Denied</h1></body></html>"
|
||||
contents200 = "<html><body><h1>Status: OK 200</h1></body></html>"
|
||||
```
|
||||
|
||||
Deal with the `/` route first:
|
||||
|
||||
* Check if authorized, if not, redirect them to the login URL
|
||||
(magical URLs taken care of magically by our `make_github_blueprint`
|
||||
function above)
|
||||
* If user is authorized (i.e., if they have gone through the OAuth
|
||||
process and given their passsword to Github and been redirected
|
||||
to your app with an OAuth token), then the next step is to
|
||||
find out some information about them.
|
||||
* Use the `github` object to call the Github API directly.
|
||||
* Decide what to do from there.
|
||||
|
||||
```
|
||||
@app.route('/')
|
||||
def index():
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
resp = github.get("/user/orgs")
|
||||
if resp.ok:
|
||||
|
||||
all_orgs = resp.json()
|
||||
for org in all_orgs:
|
||||
if org['login']=='rainbow-mind-machine':
|
||||
```
|
||||
|
||||
The next line is important to how the server works:
|
||||
if all of the criteria above have been met, we return
|
||||
a static file:
|
||||
|
||||
```
|
||||
return send_from_directory(STATIC_PATH, 'index.html')
|
||||
```
|
||||
|
||||
This is normally "bad practice," and numerous type A people
|
||||
on the internet will tell you Flask should not be used for
|
||||
serving static files, and that you should use nginx etc.,
|
||||
but these fail to igonore the following:
|
||||
|
||||
* Heroku does not let you run or configure nginx
|
||||
* For crying out loud this example is about attack rabbits
|
||||
stop taking everything so seriously
|
||||
|
||||
Now that we've got that out of the way...
|
||||
|
||||
Here's how we serve up static files. This is a total hack,
|
||||
but it works. It takes any arbitrary path supplied by the
|
||||
user, and attempts to find a corresponding file to serve up
|
||||
on disk.
|
||||
|
||||
If the user passes a file, then that file is served up.
|
||||
|
||||
If the user passes a directory, then `index.html` is served up.
|
||||
|
||||
If the user asks for a non-existent file, a 404 error is shown.
|
||||
|
||||
If the user is not allowed to view the content, they will face
|
||||
the bowel-emptying terrors of the 403 error.
|
||||
|
||||
```
|
||||
@app.route('/<path:path>')
|
||||
def catch_all(path):
|
||||
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
username = github.get("/user").json()['login']
|
||||
|
||||
rsp = app.config["RESULT_STATIC_PATH"]
|
||||
resp = github.get("/user/orgs")
|
||||
if resp.ok:
|
||||
|
||||
all_orgs = resp.json()
|
||||
for org in all_orgs:
|
||||
if org['login']=='dcppc':
|
||||
|
||||
if(path==''):
|
||||
return send_from_directory(rsp, 'index.html')
|
||||
|
||||
elif(isdir(join(rsp,path))):
|
||||
return send_from_directory(join(rsp,path),'index.html')
|
||||
|
||||
elif(isfile(join(rsp,path))):
|
||||
return send_from_directory(rsp, path)
|
||||
|
||||
else:
|
||||
return contents404
|
||||
|
||||
return contents403
|
||||
```
|
||||
|
||||
Last, set a default 404 handler, and run the app:
|
||||
|
||||
```
|
||||
@app.errorhandler(404)
|
||||
def oops(e):
|
||||
return contents404
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
```
|
||||
|
25
docs/flask_auth_github.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Authenticate Users on Github Membership
|
||||
|
||||
For the sake of simplicity, will just demonstrate how this
|
||||
works for a single route, but you can combine different
|
||||
rules into multiple routes to provide access to different
|
||||
people on different parts of a site.
|
||||
|
||||
Here is the relevant method that serves up `index.html`
|
||||
if the user is authenticated:
|
||||
|
||||
```
|
||||
@app.route('/')
|
||||
def index():
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
resp = github.get("/user")
|
||||
|
||||
if resp.ok:
|
||||
return send_from_directory(STATIC_PATH, 'index.html')
|
||||
|
||||
return contents403
|
||||
```
|
||||
|
||||
|
22
docs/flask_auth_org.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Authenticate Users on Organization or Team Membership
|
||||
|
||||
Here is how we can make access to a given page or route
|
||||
conditional on membership in an organization (in this
|
||||
example, membership in the `rainbow-mind-machine` organization
|
||||
is required for access):
|
||||
|
||||
```
|
||||
@app.route('/')
|
||||
def index():
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
resp = github.get("/user/orgs")
|
||||
if resp.ok:
|
||||
|
||||
all_orgs = resp.json()
|
||||
for org in all_orgs:
|
||||
if org['login']=='rainbow-mind-machine':
|
||||
return send_from_directory(STATIC_PATH, 'index.html')
|
||||
```
|
||||
|
27
docs/flask_auth_other.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Authenticate Users on Other Criteria
|
||||
|
||||
Suppose we wanted to do something silly like restrict
|
||||
access to a page to users with Github handles that were
|
||||
between 5 and 7 letters.
|
||||
|
||||
Here is the relevant method that serves up `index.html`
|
||||
if the user's Github handle is 5-7 letters long:
|
||||
|
||||
```
|
||||
@app.route('/')
|
||||
def index():
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
resp = github.get("/user")
|
||||
|
||||
if resp.ok:
|
||||
username = resp.json()['login']
|
||||
if len(username)>=5 and len(username)<=7:
|
||||
return send_from_directory(STATIC_PATH, 'index.html')
|
||||
|
||||
return contents403
|
||||
```
|
||||
|
||||
|
||||
|
64
docs/flask_auth_portions.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Authenticate Different Users on Different Portions of Site
|
||||
|
||||
**NOTE: if you are authenticating using membership on a team, you will need the
|
||||
team id of the team you are interested in authenticating against.**
|
||||
|
||||
For this example, let's expand the routes we're looking at
|
||||
a bit more.
|
||||
|
||||
Suppose we have two folders, `team_only` and `org_only`.
|
||||
|
||||
The `team_only` folder should only be accessible to your team, `Team Gold`.
|
||||
|
||||
The `org_only` folder should only be accessible to your organization, `Colorful Colors`.
|
||||
|
||||
The main site (i.e., all other files) should be publicly accessible.
|
||||
|
||||
```
|
||||
@app.route('/')
|
||||
def index():
|
||||
return send_from_directory(STATIC_PATH, 'index.html')
|
||||
|
||||
|
||||
@app.route('/team_only/<path:path>')
|
||||
def team_gold(path):
|
||||
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
rsp = app.config["RESULT_STATIC_PATH"]
|
||||
|
||||
resp = github.get("/user")
|
||||
if resp.ok:
|
||||
username = resp.json()['login']
|
||||
|
||||
team_id = 'XXXXX'
|
||||
|
||||
resp = github.get("/teams/%s/members/%s"%( team_id, username ))
|
||||
if resp.code==204:
|
||||
team_gold_dir = os.path.join(STATIC_PATH, 'team_only')
|
||||
return send_from_directory(team_gold_dir, 'index.html')
|
||||
return contents403
|
||||
|
||||
|
||||
@app.route('/org_only/<path:path>')
|
||||
def team_gold(path):
|
||||
|
||||
if not github.authorized:
|
||||
return redirect(url_for("github.login"))
|
||||
|
||||
rsp = app.config["RESULT_STATIC_PATH"]
|
||||
|
||||
resp = github.get("/user")
|
||||
if resp.ok:
|
||||
|
||||
my_org = 'XXXXXXXX'
|
||||
|
||||
all_orgs = resp.json()
|
||||
for org in all_orgs:
|
||||
if org['login']==my_org:
|
||||
color_org_dir = os.path.join(STATIC_PATH, 'org_only')
|
||||
return send_from_directory(color_org_dir, 'index.html')
|
||||
return contents403
|
||||
```
|
||||
|
98
docs/flask_heroku.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Deploying to Heroku
|
||||
|
||||
Once we have debugged the Flask app and we are happy with it,
|
||||
we are ready to deploy it to Heroku.
|
||||
|
||||
|
||||
## Repository Setup
|
||||
|
||||
To do this, you should set up your repo as follows:
|
||||
|
||||
Clone the repo:
|
||||
|
||||
```
|
||||
$ git clone https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
|
||||
```
|
||||
|
||||
The repo has the following structure:
|
||||
|
||||
```
|
||||
github-heroku-attack-rabbits/
|
||||
LICENSE
|
||||
README.md
|
||||
mkdocs.yml
|
||||
docs/
|
||||
index.md
|
||||
...
|
||||
mkdocs-material/
|
||||
...
|
||||
```
|
||||
|
||||
Now, inside the repo, clone the repo again,
|
||||
but this time clone the `heroku-pages` branch
|
||||
to the `site/` directory:
|
||||
|
||||
```
|
||||
$ cd github-heroku-attack-rabbits/
|
||||
$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
|
||||
```
|
||||
|
||||
|
||||
## Heroku Deploy Process
|
||||
|
||||
To deploy content to Heroku, we add our Heroku project as a git remote
|
||||
(see the [heroku](heroku.md) page for how to do that) and then push to
|
||||
to the master branch of the heroku remote git repo. Changes are pulled
|
||||
in by Heroku and the app is restarted each time you run `git push`.
|
||||
|
||||
We walk through the steps below.
|
||||
|
||||
|
||||
## Heroku Login
|
||||
|
||||
From the `site/` directory containing the contents of the `heroku-pages` branch,
|
||||
that is, containing the Python flask app, log in to Heroku:
|
||||
|
||||
```
|
||||
$ heroku login
|
||||
```
|
||||
|
||||
|
||||
## Add Heroku Remote to `heroku-pages` Branch
|
||||
|
||||
Now have Heroku add the proper git remote address:
|
||||
|
||||
```
|
||||
$ heroku git:remote -a <heroku-app-name>
|
||||
```
|
||||
|
||||
Now you're ready to deploy to Heroku.
|
||||
|
||||
|
||||
## Deploy to Heroku
|
||||
|
||||
Double check your app is ready, then deploy:
|
||||
|
||||
```
|
||||
$ git push heroku heroku-pages:master
|
||||
```
|
||||
|
||||
This will push the local branch `heroku-pages` to
|
||||
the remote branch `master` on the `heroku` remote.
|
||||
This should begin a pre-commit hook where Heroku
|
||||
compiles your Python app. You should get the green
|
||||
light, if you tested your app locally and everything
|
||||
was good to go.
|
||||
|
||||
|
||||
## Check Your Heroku App
|
||||
|
||||
Your Heroku app will be available at
|
||||
|
||||
```
|
||||
https://<heroku-app-name>.herokuapp.com
|
||||
```
|
||||
|
||||
You should see your Python flask app
|
||||
show up shortly.
|
||||
|
42
docs/flask_local.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Testing Flask App Locally
|
||||
|
||||
We set up the Github App to use a callback of `https://localhost:5000/login/github/authorized`
|
||||
so that we could test the app locally. Now it is time to test the app locally.
|
||||
|
||||
The application needs access to your Github app id and token. Those are provided
|
||||
via the `GITHUB_OAUTH_CLIENT_{ID,SECRET}` environment variables. Set these
|
||||
when you run the actual python command to run the server:
|
||||
|
||||
```
|
||||
$ GITHUB_OAUTH_CLIENT_ID="xxxxxxx" \
|
||||
GITHUB_OAUTH_CLIENT_SECRET="xxxxxxx" \
|
||||
OAUTHLIB_INSECURE_TRANSPORT=true \
|
||||
python github.py
|
||||
```
|
||||
|
||||
This runs the Flask server on port 5000, where it will wait for a visitor.
|
||||
The way we have our application written in this example, the main `/` route
|
||||
will redirect the user to a Github login screen immediately, but you could
|
||||
also present the user with a friendly welcome page when they go to `/`,
|
||||
and only redirect them to the Github login prompt when they visit a
|
||||
URL like `/login` or `/auth`.
|
||||
|
||||
Once you run the above command, open the following URL in your browser:
|
||||
|
||||
```
|
||||
http://localhost:5000/
|
||||
```
|
||||
|
||||
**NOTE: Make sure you are logged out of Github and that you clear your cookies
|
||||
if you are already logged in as one user and wish to authenticate as another.
|
||||
The login is _very_ persistent so you may need to close and re-open your browser.**
|
||||
|
||||
Visiting the address above will result in your being redirected to a Github
|
||||
login page. Once you login, Github will redirect the user back to the
|
||||
github-heroku-attack-rabbits application with a token that the application
|
||||
can use to perform actions on behalf of the user.
|
||||
|
||||
## Next Step?
|
||||
|
||||
If the app works, the next step is to deploy to Heroku.
|
||||
|
57
docs/github.md
Normal file
@ -0,0 +1,57 @@
|
||||
## get started with github
|
||||
|
||||
We mentioned on the [heroku](heroku.md) page that heroku
|
||||
creates a remote git repository to hold the files you
|
||||
want to host.
|
||||
|
||||
To use the contents of a Github repository on Heroku,
|
||||
just treat it like another git remote, no special setup
|
||||
is needed.
|
||||
|
||||
However, to set up your Github-Heroku attack rabbits to
|
||||
authenticate a user via Github, and mercilessly attack
|
||||
all intruders, you must create a Github OAuth App.
|
||||
|
||||
### Creating Github OAuth App
|
||||
|
||||
Log into Github
|
||||
|
||||
Go to Settings
|
||||
|
||||
Click "Developer Settings" on the left side
|
||||
|
||||
Click "New OAuth App" button in upper right
|
||||
|
||||
**What do these settings mean?**
|
||||
|
||||
* **Application name** is what will be shown to users when they visit
|
||||
a page protected by the attack rabbits and are prompted for
|
||||
their password by Github.
|
||||
|
||||
* **Homepage URL/Application description** are for users who want to know more
|
||||
about your killer attack rabbit Github app
|
||||
|
||||
* **Authorization callback URL** is the URL that the users will be sent to
|
||||
once they authenticate with Github and they are granted an OAuth token.
|
||||
This is the magic ingredient that allows you to take actions on behalf
|
||||
of the account logging in.
|
||||
|
||||
In this guide we'll cover the case of checking membership in organizations or teams,
|
||||
but what your attack rabbits end up doing to determine if a user is allowed to
|
||||
access your secret pages is up to you.
|
||||
|
||||
## Values to use
|
||||
|
||||
You should set your own values for the **name** and **description** fields.
|
||||
|
||||
The **home URL** is not actually necessary - it is simply provided for users to
|
||||
get more information about your app.
|
||||
|
||||
The most important is the **callback URL**, which should be set to:
|
||||
|
||||
http://localhost:5000/login/github/authorized
|
||||
|
||||
This is for testing locally *only*.
|
||||
|
||||
Don't use HTTPS in the callback URL!
|
||||
|
67
docs/heroku.md
Normal file
@ -0,0 +1,67 @@
|
||||
# create heroku app
|
||||
|
||||
|
||||
### Heroku toolbelt
|
||||
|
||||
Heroku offers a really nice command line interface tool called
|
||||
Heroku Toolbelt. It is available through Homebrew and Aptitude:
|
||||
|
||||
```
|
||||
$ brew install heroku # from Mac
|
||||
|
||||
$ apt-get install heroku # from Ubuntu
|
||||
```
|
||||
|
||||
It is then available on the command line as `heroku`.
|
||||
|
||||
The first thing you should do is authenticate with
|
||||
your Heroku account by running
|
||||
|
||||
```
|
||||
$ heroku login
|
||||
```
|
||||
|
||||
We will use this command line application for the following tasks:
|
||||
|
||||
* Create a git remote to point to the right Heroku git remote location
|
||||
* Set environment variables (for e.g. secret keys) on the remote Heroku instance
|
||||
* Get information (logs, status, etc.) about your Heroku app
|
||||
|
||||
We will cover these commands as they come up.
|
||||
|
||||
|
||||
### Create heroku app
|
||||
|
||||
Start by creating a heroku app.
|
||||
|
||||
* Each heroku app must have a unique name
|
||||
* Each heroku app creates a remote git repo
|
||||
* Master branch is what Heroku deploys publicly on herokuapps.com
|
||||
* You will also need heroku CLI to link your github repo to your heroku app
|
||||
|
||||
|
||||
### Where heroku app lives
|
||||
|
||||
Suppose you are creating an app called `my-cool-app`
|
||||
on heroku. Then your application will be hosted by
|
||||
Heroku and will be available at the URL:
|
||||
|
||||
```
|
||||
https://my-cool-app.herokuapp.com
|
||||
```
|
||||
|
||||
### How heroku apps works
|
||||
|
||||
If you have used Github Pages before, Heroku uses a similar
|
||||
model (live hosting one particular branch of a git repository).
|
||||
However, Heroku is different because you can run dynamic scripts
|
||||
using Python, Ruby, PHP, etc.
|
||||
|
||||
To change the content of your Heroku app, just change the contents
|
||||
of the repository, and push to master (push to the master branch of
|
||||
the remote Heroku repository).
|
||||
|
||||
You will need to structure your repository carefully.
|
||||
That's what this page is here to help you do.
|
||||
Heroku can figure out the rest from there.
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
BIN
docs/img/warnico.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
docs/img/warning.png
Normal file
After Width: | Height: | Size: 46 KiB |
92
docs/index.md
Normal file
@ -0,0 +1,92 @@
|
||||
# github-heroku-attack-rabbits
|
||||
|
||||
## What's this business all about, then?
|
||||
|
||||
This repository helps you put access control into place to protect your secret pages by (deep breath):
|
||||
|
||||
hosting your secret page of static and/or dynamic content by using a free Heroku app
|
||||
running a Python Flask server that uses Flask-Dance to authenticate visitors
|
||||
with Github using OAuth which allows you fine-grained access control for your pages
|
||||
using user attributes like organization or team membership or even things like how many
|
||||
vowels a user has in their username.
|
||||
|
||||
Also, did I mention the attack rabbits?
|
||||
|
||||

|
||||
|
||||
|
||||
## Where is everything?
|
||||
|
||||
Final pages:
|
||||
|
||||
* The finished product (pages on Heroku protected by attack rabbits)
|
||||
is at [github-heroku-attack-rabbits.herokuapp.com](https://github-heroku-attack-rabbits.herokuapp.com)
|
||||
|
||||
* The documentation is at [pages.charlesreid1.com/github-heroku-attack-rabbits](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
|
||||
|
||||
Two branches in this repo compose the github-heroku-attack-rabbits documentation:
|
||||
|
||||
* (**YOU ARE HERE**) The [docs](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs) branch
|
||||
contains the files needed to generate the
|
||||
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
|
||||
|
||||
* The [gh-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/gh-pages) branch
|
||||
contains the static files generated from the documentation.
|
||||
The contents of this branch compose the
|
||||
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
|
||||
|
||||
Two branches illustrate github-heroku-attack-rabbits in practice:
|
||||
|
||||
* The [secret](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/secret) branch contains the files needed to create the secret page.
|
||||
This repository is public, so obviously these aren't *actually* secret,
|
||||
but in practice this would be in a protected repository.
|
||||
|
||||
* The [heroku-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/heroku-pages) branch
|
||||
contains the content that is actually pushed to Heroku - that is,
|
||||
the final Flask app.
|
||||
|
||||
|
||||
## Contents
|
||||
|
||||
An overview of the steps:
|
||||
|
||||
[Get Started with Heroku](heroku.md)
|
||||
|
||||
[Get Started with Github](github.md)
|
||||
|
||||
[Initialize Repository: Branches](repo.md)
|
||||
|
||||
[Create a Flask App using Flask-Dance](flask.md)
|
||||
|
||||
* [Authenticate users based on Github membership only](flask_auth_github.md)
|
||||
* [Authenticate users based on organization or team membership](flask_auth_org.md)
|
||||
* [Authenticate users based on some other criteria](flask_auth_other.md)
|
||||
* [Protection portions of the site](flask_auth_portions.md)
|
||||
|
||||
[Test Flask App Locally](flask_local.md)
|
||||
|
||||
[Deploying Flask App to Heroku](flask_heroku.md)
|
||||
|
||||
[Custom Domains](custom_domains.md)
|
||||
|
||||
|
||||
## Links
|
||||
|
||||
Python software used:
|
||||
|
||||
* [Flask](http://flask.pocoo.org/)
|
||||
* [Flask-dance](https://github.com/singingwolfboy/flask-dance)
|
||||
* [Flask-dance-github](https://github.com/singingwolfboy/flask-dance-github)
|
||||
* [mkdocs-material (documentation theme)](https://github.com/squidfunk/mkdocs-material)
|
||||
* [mkdocs (documentation)](http://www.mkdocs.org/)
|
||||
|
||||
Commercial services:
|
||||
|
||||
* [Heroku](https://heroku.com)
|
||||
* [Github](https://github.com)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This is released under the [WTFPL](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE).
|
||||
|
110
docs/repo.md
Normal file
@ -0,0 +1,110 @@
|
||||
# Initialize Git Repository
|
||||
|
||||
Let's talk through how a repository should be laid out
|
||||
if we're going to be hosting a Flask app on Heroku.
|
||||
|
||||
## Branches
|
||||
|
||||
We will need a minimum of two branches. Here we specify
|
||||
the names that these branches will have in your Github repo,
|
||||
**which is different from the names of the branches on Heroku**:
|
||||
|
||||
Branches on Github:
|
||||
|
||||
* `heroku-pages` - this branch contains the content that Heroku will host.
|
||||
Specifically, it contains the Flask application in a `.py` file,
|
||||
and a few other files to help Heroku determine how to run the app
|
||||
and what to install.
|
||||
|
||||
* `master` - this branch contains the content used to generate the documentation
|
||||
and page content that is being hosted behind the Heroku attack sheep.
|
||||
The documentation you are reading right now is from the master branch,
|
||||
and was made with `mkdocs`.
|
||||
|
||||
On Heroku, we only have a single branch:
|
||||
|
||||
* `master` (Heroku) maps to `heroku-pages` (Github)
|
||||
|
||||
## Repo Layout
|
||||
|
||||
Let's talk about the layout of the repository.
|
||||
|
||||
If you wish to build the site in order to deploy it to Heroku,
|
||||
you should clone the `master` branch (preparing to make the
|
||||
content for your attack sheep-protected page):
|
||||
|
||||
```
|
||||
$ git clone -b master https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
|
||||
$ cd github-heroku-attack-rabbits
|
||||
```
|
||||
|
||||
Once you are *inside* the master branch, clone the repo again,
|
||||
but this time clone the `heroku-pages` branch, and clone it
|
||||
to the `site/` folder:
|
||||
|
||||
```
|
||||
$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
|
||||
$ cd site
|
||||
```
|
||||
|
||||
Now you will want to set up the Heroku remote:
|
||||
|
||||
```
|
||||
$ heroku git:remote -a my-cool-project
|
||||
```
|
||||
|
||||
The layout should now be:
|
||||
|
||||
```
|
||||
my-cool-project-repo/ <-- my-cool-project repo pointing to master branch
|
||||
|
||||
docs/ \
|
||||
index.md |
|
||||
heroku.md | <-- mkdocs files
|
||||
... | (can use any static content generator:
|
||||
| pelican, sphinx, etc.)
|
||||
mkdocs.yml /
|
||||
|
||||
site/ <-- my-cool-project repo pointing to heroku-pages branch
|
||||
|
||||
Procfile \
|
||||
github.py | <-- heroku python app files
|
||||
requirements.txt | (can also use ruby, php, js, etc.)
|
||||
runtime.txt | (can also use ruby, php, js, etc.)
|
||||
... /
|
||||
|
||||
content/ \
|
||||
index.html | <-- static content hosted by Flask
|
||||
sitemap.xml |
|
||||
... /
|
||||
```
|
||||
|
||||
|
||||
## Workflow
|
||||
|
||||
Once you have things set up according to the instructions and diagram above,
|
||||
you're ready to run the push-to-deploy workflow and start running your secret
|
||||
site on Heroku.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
29
mkdocs.yml
@ -1,22 +1,29 @@
|
||||
site_name: This Is The Secret Site
|
||||
site_url: https://github-heroku-attack-rabbits.herokuapp.com
|
||||
site_name: github-heroku-attack-rabbits
|
||||
site_url: https://pages.charlesreid1.com/github-heroku-attack-rabbits
|
||||
repo_name: charlesreid1/github-heroku-attack-rabbits
|
||||
repo_url: https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits
|
||||
edit_uri: ""
|
||||
|
||||
# Note: normally this whole branch/repo would be secret,
|
||||
# otherwise everyone could bypass your attack rabbits
|
||||
# by simply browsing your repository.
|
||||
|
||||
pages:
|
||||
- 'Index' : 'index.md'
|
||||
- 'Fish Slapping': 'fishslap.md'
|
||||
- 'Silly Walks': 'sillywalk.md'
|
||||
- 'Get Started with Heroku': 'heroku.md'
|
||||
- 'Get Started with Github': 'github.md'
|
||||
- 'Initialize Repository: Branches': 'repo.md'
|
||||
- 'Create a Flask App using Flask-Dance': 'flask.md'
|
||||
- 'Flask':
|
||||
- 'Authenticate users based on Github membership only': 'flask_auth_github.md'
|
||||
- 'Authenticate users based on organization or team membership': 'flask_auth_org.md'
|
||||
- 'Authenticate users based on some other criteria': 'flask_auth_other.md'
|
||||
- 'Protection portions of the site': 'flask_auth_portions.md'
|
||||
- 'Test Flask App Locally': 'flask_local.md'
|
||||
- 'Deploying Flask App to Heroku': 'flask_heroku.md'
|
||||
- 'Custom Domains': 'custom_domains.md'
|
||||
|
||||
copyright: 'Copyright © 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />'
|
||||
|
||||
docs_dir: secret_docs
|
||||
site_dir: site/content
|
||||
docs_dir: docs
|
||||
site_dir: site
|
||||
|
||||
theme:
|
||||
|
||||
@ -25,8 +32,8 @@ theme:
|
||||
|
||||
# pretty colors! see https://squidfunk.github.io/mkdocs-material/getting-started/#primary-colors
|
||||
palette:
|
||||
primary: 'teal'
|
||||
accent: 'teal'
|
||||
primary: 'blue grey'
|
||||
accent: 'blue grey'
|
||||
|
||||
logo: 'img/bunny.png'
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
.md-typeset h1 { font-weight: 600; }
|
||||
.md-typeset h2 { font-weight: 600; }
|
||||
.md-typeset h3 { font-weight: 600; }
|
||||
.md-typeset h4 { font-weight: 600; }
|
||||
|
||||
body {
|
||||
background-color: #f2f9f7;
|
||||
}
|
||||
div.body {
|
||||
background-color: #f2f9f7;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
# The Secret Society of the Fish Slapping Dance
|
||||
|
||||
Welcome, and congratulations on having an even number of vowels in your Github handle.
|
||||
|
||||
And now for something completely expected:
|
||||
|
||||
[Fish-Slapping Dance](https://www.youtube.com/watch?v=T8XeDvKqI4E)
|
||||
|
Before Width: | Height: | Size: 598 KiB |
Before Width: | Height: | Size: 621 KiB |
Before Width: | Height: | Size: 34 KiB |
@ -1,16 +0,0 @@
|
||||
# Secret Index
|
||||
|
||||
This is an index of secret pages. Note that this page is not protected.
|
||||
|
||||
You will be asked to authenticate when you click the links below.
|
||||
|
||||
If your username has an **even number of vowels**, you are a member
|
||||
of the [Secret Society of the Fish Slappers](fishslap.md).
|
||||
Click the link to log in and proceed, or else be attacked by
|
||||
the Github-Heroku attack rabbits.
|
||||
|
||||
If your username has an **odd number of vowels**, you are a member
|
||||
of the [Secret Ministerial Department for Theoretical Silly Walk Studies](sillywalk.md).
|
||||
Click the link to log in and proceed, or else be attacked by
|
||||
the Github-Heroku attack rabbits.
|
||||
|
@ -1,9 +0,0 @@
|
||||
# The Secret Ministry of Silly Walks
|
||||
|
||||
Welcome, and congratulations on having an odd number of vowels in your Github handle.
|
||||
|
||||
And now for something completely expected:
|
||||
|
||||
|
||||
[Ministry of Sily Walks](https://www.youtube.com/watch?v=IqhlQfXUk7w)
|
||||
|