Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
snf-ganeti
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
itminedu
snf-ganeti
Commits
be500c29
Commit
be500c29
authored
Dec 19, 2008
by
Michael Hanselmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ganeti.http: Add support for basic HTTP authentication
As per RFC2617. Reviewed-by: amishchenko
parent
f8bd7df3
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
200 additions
and
0 deletions
+200
-0
Makefile.am
Makefile.am
+1
-0
lib/http/auth.py
lib/http/auth.py
+199
-0
No files found.
Makefile.am
View file @
be500c29
...
...
@@ -102,6 +102,7 @@ rapi_PYTHON = \
http_PYTHON
=
\
lib/http/__init__.py
\
lib/http/auth.py
\
lib/http/client.py
\
lib/http/server.py
...
...
lib/http/auth.py
0 → 100644
View file @
be500c29
#
#
# Copyright (C) 2007, 2008 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""HTTP authentication module.
"""
import
logging
import
time
import
re
import
base64
import
binascii
from
ganeti
import
constants
from
ganeti
import
utils
from
ganeti
import
http
from
cStringIO
import
StringIO
# Digest types from RFC2617
HTTP_BASIC_AUTH
=
"Basic"
HTTP_DIGEST_AUTH
=
"Digest"
# Not exactly as described in RFC2616, section 2.2, but good enough
_NOQUOTE
=
re
.
compile
(
r
"^[-_a-z0-9]$"
,
re
.
I
)
def
_FormatAuthHeader
(
scheme
,
params
):
"""Formats WWW-Authentication header value as per RFC2617, section 1.2
@type scheme: str
@param scheme: Authentication scheme
@type params: dict
@param params: Additional parameters
@rtype: str
@return: Formatted header value
"""
buf
=
StringIO
()
buf
.
write
(
scheme
)
for
name
,
value
in
params
.
iteritems
():
buf
.
write
(
" "
)
buf
.
write
(
name
)
buf
.
write
(
"="
)
if
_NOQUOTE
.
match
(
value
):
buf
.
write
(
value
)
else
:
buf
.
write
(
"
\"
"
)
# TODO: Better quoting
buf
.
write
(
value
.
replace
(
"
\"
"
,
"
\\\"
"
))
buf
.
write
(
"
\"
"
)
return
buf
.
getvalue
()
class
HttpServerRequestAuthentication
(
object
):
# Default authentication realm
AUTH_REALM
=
None
def
GetAuthRealm
(
self
,
req
):
"""Returns the authentication realm for a request.
MAY be overriden by a subclass, which then can return different realms for
different paths. Returning "None" means no authentication is needed for a
request.
@type req: L{http.server._HttpServerRequest}
@param req: HTTP request context
@rtype: str or None
@return: Authentication realm
"""
return
self
.
AUTH_REALM
def
PreHandleRequest
(
self
,
req
):
"""Called before a request is handled.
@type req: L{http.server._HttpServerRequest}
@param req: HTTP request context
"""
realm
=
self
.
GetAuthRealm
(
req
)
# Authentication required?
if
realm
is
None
:
return
# Check "Authorization" header
if
self
.
_CheckAuthorization
(
req
):
# User successfully authenticated
return
# Send 401 Unauthorized response
params
=
{
"realm"
:
realm
,
}
# TODO: Support for Digest authentication (RFC2617, section 3).
# TODO: Support for more than one WWW-Authenticate header with the same
# response (RFC2617, section 4.6).
headers
=
{
http
.
HTTP_WWW_AUTHENTICATE
:
_FormatAuthHeader
(
HTTP_BASIC_AUTH
,
params
),
}
raise
http
.
HttpUnauthorized
(
headers
=
headers
)
def
_CheckAuthorization
(
self
,
req
):
"""Checks "Authorization" header sent by client.
@type req: L{http.server._HttpServerRequest}
@param req: HTTP request context
@type credentials: str
@param credentials: Credentials sent
@rtype: bool
@return: Whether user is allowed to execute request
"""
credentials
=
req
.
request_headers
.
get
(
http
.
HTTP_AUTHORIZATION
,
None
)
if
not
credentials
:
return
False
# Extract scheme
parts
=
credentials
.
strip
().
split
(
None
,
2
)
if
len
(
parts
)
<
1
:
# Missing scheme
return
False
# RFC2617, section 1.2: "[...] It uses an extensible, case-insensitive
# token to identify the authentication scheme [...]"
scheme
=
parts
[
0
].
lower
()
if
scheme
==
HTTP_BASIC_AUTH
.
lower
():
# Do basic authentication
if
len
(
parts
)
<
2
:
raise
http
.
HttpBadRequest
(
message
=
(
"Basic authentication requires"
" credentials"
))
return
self
.
_CheckBasicAuthorization
(
req
,
parts
[
1
])
elif
scheme
==
HTTP_DIGEST_AUTH
.
lower
():
# TODO: Implement digest authentication
# RFC2617, section 3.3: "Note that the HTTP server does not actually need
# to know the user's cleartext password. As long as H(A1) is available to
# the server, the validity of an Authorization header may be verified."
pass
# Unsupported authentication scheme
return
False
def
_CheckBasicAuthorization
(
self
,
req
,
input
):
"""Checks credentials sent for basic authentication.
@type req: L{http.server._HttpServerRequest}
@param req: HTTP request context
@type input: str
@param input: Username and password encoded as Base64
@rtype: bool
@return: Whether user is allowed to execute request
"""
try
:
creds
=
base64
.
b64decode
(
input
.
encode
(
'ascii'
)).
decode
(
'ascii'
)
except
(
TypeError
,
binascii
.
Error
,
UnicodeError
):
logging
.
exception
(
"Error when decoding Basic authentication credentials"
)
return
False
if
":"
not
in
creds
:
return
False
(
user
,
password
)
=
creds
.
split
(
":"
,
1
)
return
self
.
Authenticate
(
req
,
user
,
password
)
def
AuthenticateBasic
(
self
,
req
,
user
,
password
):
"""Checks the password for a user.
This function MUST be overriden by a subclass.
"""
raise
NotImplementedError
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment