def cboxOpen():
'''Returns a WOPISrc target and an access token to be passed to Microsoft Office online for
accessing a given file for a given user. This is the most sensitive call as it provides direct
access to any user's file, therefore it is protected both by IP and a shared secret. The shared
secret protection is disabled when running in plain http mode for testing purposes.'''
Wopi.refreshconfig()
req = flask.request
# if running in https mode, first check if the shared secret matches ours
if Wopi.useHttps and ('Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.ocsecret):
Wopi.log.warning('msg="cboxOpen: unauthorized access attempt, missing authorization token" client="%s"' % req.remote_addr)
return 'Client not authorized', httplib.UNAUTHORIZED
# now validate the user identity and deny root access
try:
ruid = int(req.args['ruid'])
rgid = int(req.args['rgid'])
if ruid == 0 or rgid == 0:
raise ValueError
except ValueError:
Wopi.log.warning('msg="cboxOpen: invalid user/group in request" client="%s" user="%s:%s"' % \
(req.remote_addr, req.args['ruid'], req.args['rgid']))
return 'Client not authorized', httplib.UNAUTHORIZED
# then resolve the client: only our OwnCloud servers shall use this API
allowedclients = Wopi.config.get('general', 'allowedclients').split()
for c in allowedclients:
try:
for ip in socket.getaddrinfo(c, None):
if ip[4][0] == req.remote_addr:
# we got a match, generate the access token
filename = urllib.unquote(req.args['filename'])
canedit = 'canedit' in req.args and req.args['canedit'].lower() == 'true'
username = req.args['username'] if 'username' in req.args else ''
folderurl = urllib.unquote(req.args['folderurl'])
try:
Wopi.log.info('msg="cboxOpen: access granted, generating token" client="%s" user="%d:%d" friendlyname="%s" canedit="%s"' % \
(req.remote_addr, ruid, rgid, username, canedit))
inode, acctok = _generateAccessToken(str(ruid), str(rgid), filename, canedit, username, folderurl)
# return an URL-encoded WOPISrc URL for the Office Online server
return urllib.quote_plus('%s/wopi/files/%s' % (_ourHostName(), inode)) + \
'&access_token=%s' % acctok # no need to URL-encode the JWT token
except IOError:
return 'Remote error or file not found', httplib.NOT_FOUND
except socket.gaierror:
Wopi.log.warning('msg="cboxOpen: %s found in configured allowed clients but unknown by DNS resolution, ignoring"' % c)
# no match found, fail
Wopi.log.warning('msg="cboxOpen: unauthorized access attempt, client IP not whitelisted" client="%s"' % req.remote_addr)
return 'Client not authorized', httplib.UNAUTHORIZED
python类UNAUTHORIZED的实例源码
def ReadHttpResponse(conn, expect_status=200, ignore_404=True):
"""Reads an http response from a connection into a string buffer.
Args:
conn: An HTTPSConnection or HTTPConnection created by CreateHttpConn, above.
expect_status: Success is indicated by this status in the response.
ignore_404: For many requests, gerrit-on-borg will return 404 if the request
doesn't match the database contents. In most such cases, we
want the API to return None rather than raise an Exception.
Returns: A string buffer containing the connection's reply.
"""
sleep_time = 0.5
for idx in range(TRY_LIMIT):
response = conn.getresponse()
# Check if this is an authentication issue.
www_authenticate = response.getheader('www-authenticate')
if (response.status in (httplib.UNAUTHORIZED, httplib.FOUND) and
www_authenticate):
auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I)
host = auth_match.group(1) if auth_match else conn.req_host
reason = ('Authentication failed. Please make sure your .netrc file '
'has credentials for %s' % host)
raise GerritAuthenticationError(response.status, reason)
# If response.status < 500 then the result is final; break retry loop.
if response.status < 500:
LOGGER.debug('got response %d for %s %s', response.status,
conn.req_params['method'], conn.req_params['url'])
break
# A status >=500 is assumed to be a possible transient error; retry.
http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0')
LOGGER.warn('A transient error occurred while querying %s:\n'
'%s %s %s\n'
'%s %d %s',
conn.host, conn.req_params['method'], conn.req_params['url'],
http_version, http_version, response.status, response.reason)
if TRY_LIMIT - idx > 1:
LOGGER.warn('... will retry %d more times.', TRY_LIMIT - idx - 1)
time.sleep(sleep_time)
sleep_time = sleep_time * 2
req_host = conn.req_host
req_params = conn.req_params
conn = GetConnectionClass()(req_host)
conn.req_host = req_host
conn.req_params = req_params
conn.request(**req_params)
if ignore_404 and response.status == 404:
return StringIO()
if response.status != expect_status:
reason = '%s: %s' % (response.reason, response.read())
raise GerritError(response.status, reason)
return StringIO(response.read())
def check_status(status, expected, path, headers=None,
resp_headers=None, body=None, extras=None):
"""Check HTTP response status is expected.
Args:
status: HTTP response status. int.
expected: a list of expected statuses. A list of ints.
path: filename or a path prefix.
headers: HTTP request headers.
resp_headers: HTTP response headers.
body: HTTP response body.
extras: extra info to be logged verbatim if error occurs.
Raises:
AuthorizationError: if authorization failed.
NotFoundError: if an object that's expected to exist doesn't.
TimeoutError: if HTTP request timed out.
ServerError: if server experienced some errors.
FatalError: if any other unexpected errors occurred.
"""
if status in expected:
return
msg = ('Expect status %r from Google Storage. But got status %d.\n'
'Path: %r.\n'
'Request headers: %r.\n'
'Response headers: %r.\n'
'Body: %r.\n'
'Extra info: %r.\n' %
(expected, status, path, headers, resp_headers, body, extras))
if status == httplib.UNAUTHORIZED:
raise AuthorizationError(msg)
elif status == httplib.FORBIDDEN:
raise ForbiddenError(msg)
elif status == httplib.NOT_FOUND:
raise NotFoundError(msg)
elif status == httplib.REQUEST_TIMEOUT:
raise TimeoutError(msg)
elif status == httplib.REQUESTED_RANGE_NOT_SATISFIABLE:
raise InvalidRange(msg)
elif (status == httplib.OK and 308 in expected and
httplib.OK not in expected):
raise FileClosedError(msg)
elif status >= 500:
raise ServerError(msg)
else:
raise FatalError(msg)
def _authenticate_with_kerberos(conn_info, url, agent, gss_client=None):
service = '{0}@{1}'.format(conn_info.scheme.upper(), conn_info.hostname)
if gss_client is None:
gss_client = AuthGSSClient(
service,
conn_info)
base64_client_data = yield gss_client.get_base64_client_data()
auth = 'Kerberos {0}'.format(base64_client_data)
k_headers = Headers(_CONTENT_TYPE)
k_headers.addRawHeader('Authorization', auth)
k_headers.addRawHeader('Content-Length', '0')
response = yield agent.request('POST', url, k_headers, None)
auth_header = response.headers.getRawHeaders('WWW-Authenticate')[0]
auth_details = get_auth_details(auth_header)
if response.code == httplib.UNAUTHORIZED:
try:
if auth_details:
gss_client._step(auth_details)
except kerberos.GSSError as e:
msg = "HTTP Unauthorized received on kerberos initialization. "\
"Kerberos error code {0}: {1}.".format(e.args[1][1], e.args[1][0])
raise Exception(msg)
raise UnauthorizedError(
"HTTP Unauthorized received on initial kerberos request. Check username and password")
elif response.code == httplib.FORBIDDEN:
raise ForbiddenError(
"Forbidden. Check WinRM port and version.")
elif response.code != httplib.OK:
proto = _StringProtocol()
response.deliverBody(proto)
xml_str = yield proto.d
xml_str = gss_client.decrypt_body(xml_str)
raise Exception(
"status code {0} received on initial kerberos request {1}"
.format(response.code, xml_str))
if not auth_details:
raise Exception(
'negotiate not found in WWW-Authenticate header: {0}'
.format(auth_header))
k_username = gss_client.get_username(auth_details)
log.debug('kerberos auth successful for user: {0} / {1} '
.format(conn_info.username, k_username))
defer.returnValue(gss_client)