Whole-site password protection #88
It's now possible to require HTTP authentication for all of the Web
interface (not only push/pull). This isn't available from the command
line.
Note that when both whole-site password protection and Smart HTTP mode
is enabled, push is allowed by default. It can be disallowed using the
'disable_push' option.
Jonas Haag
7 years ago
60 | 60 | self.add_url_rule(rule, view_func=getattr(views, endpoint)) |
61 | 61 | |
62 | 62 | |
63 | def make_app(repos, site_name, use_smarthttp=False, htdigest_file=None): | |
63 | def make_app(repos, site_name, use_smarthttp=False, htdigest_file=None, | |
64 | require_browser_auth=False, disable_push=False): | |
64 | 65 | """ |
65 | 66 | Returns a WSGI app with all the features (smarthttp, authentication) |
66 | 67 | already patched in. |
68 | ||
69 | :param repos: List of paths of repositories to serve. | |
70 | :param site_name: Name of the Web site (e.g. "John Doe's Git Repositories") | |
71 | :param use_smarthttp: Enable Git Smart HTTP mode, which makes it possible to | |
72 | pull from the served repositories. If `htdigest_file` is set as well, | |
73 | also allow to push for authenticated users. | |
74 | :param require_browser_auth: Require HTTP authentication according to the | |
75 | credentials in `htdigest_file` for ALL access to the Web interface. | |
76 | Requires the `htdigest_file` option to be set. | |
77 | :param disable_push: Disable push support. This is required in case both | |
78 | `use_smarthttp` and `require_browser_auth` (and thus `htdigest_file`) | |
79 | are set, but push should not be supported. | |
80 | :param htdigest_file: A *file-like* object that contains the HTTP auth credentials. | |
67 | 81 | """ |
68 | 82 | app = Klaus( |
69 | 83 | repos, |
83 | 97 | backend=dulwich_backend, |
84 | 98 | fallback_app=app.wsgi_app, |
85 | 99 | ) |
100 | dulwich_wrapped_app = utils.SubUri(dulwich_wrapped_app) | |
86 | 101 | |
87 | 102 | # `receive-pack` is requested by the "client" on a push |
88 | 103 | # (the "server" is asked to *receive* packs), i.e. we need to secure |
99 | 114 | # failed for /info/refs, but since it's used to upload stuff to the server |
100 | 115 | # we must secure it anyway for security reasons. |
101 | 116 | PATTERN = r'^/[^/]+/(info/refs\?service=git-receive-pack|git-receive-pack)$' |
102 | if htdigest_file: | |
117 | if htdigest_file and not disable_push: | |
103 | 118 | # .htdigest file given. Use it to read the push-er credentials from. |
104 | app.wsgi_app = httpauth.DigestFileHttpAuthMiddleware( | |
105 | htdigest_file, | |
106 | wsgi_app=utils.SubUri(dulwich_wrapped_app), | |
107 | routes=[PATTERN], | |
108 | ) | |
119 | if require_browser_auth: | |
120 | # No need to secure push'ing if we already require HTTP auth | |
121 | # for all of the Web interface. | |
122 | app.wsgi_app = dulwich_wrapped_app | |
123 | else: | |
124 | # Web interface isn't already secured. Require authentication for push'ing. | |
125 | app.wsgi_app = httpauth.DigestFileHttpAuthMiddleware( | |
126 | htdigest_file, | |
127 | wsgi_app=dulwich_wrapped_app, | |
128 | routes=[PATTERN], | |
129 | ) | |
109 | 130 | else: |
110 | # no .htdigest file given. Disable push-ing. Semantically we should | |
131 | # No .htdigest file given. Disable push-ing. Semantically we should | |
111 | 132 | # use HTTP 403 here but since that results in freaky error messages |
112 | 133 | # (see above) we keep asking for authentication (401) instead. |
113 | 134 | # Git will print a nice error message after a few tries. |
114 | 135 | app.wsgi_app = httpauth.AlwaysFailingAuthMiddleware( |
115 | wsgi_app=utils.SubUri(dulwich_wrapped_app), | |
136 | wsgi_app=dulwich_wrapped_app, | |
116 | 137 | routes=[PATTERN], |
117 | 138 | ) |
118 | 139 | |
140 | if require_browser_auth: | |
141 | app.wsgi_app = httpauth.DigestFileHttpAuthMiddleware( | |
142 | htdigest_file, | |
143 | wsgi_app=app.wsgi_app | |
144 | ) | |
145 | ||
119 | 146 | return app |