72
def extract_oauth_access_token(request):
73
"""Find the OAuth access token that signed the given request.
75
:param request: An incoming request.
77
:return: an IOAuthAccessToken, or None if the request is not
80
:raise Unauthorized: If the token is invalid or the request is an
81
anonymously-signed request that doesn't meet our requirements.
83
# Fetch OAuth authorization information from the request.
84
form = get_oauth_authorization(request)
86
consumer_key = form.get('oauth_consumer_key')
87
consumers = getUtility(IOAuthConsumerSet)
88
consumer = consumers.getByKey(consumer_key)
89
token_key = form.get('oauth_token')
90
anonymous_request = (token_key == '')
92
if consumer_key is None:
93
# Either the client's OAuth implementation is broken, or
94
# the user is trying to make an unauthenticated request
95
# using wget or another OAuth-ignorant application.
96
# Try to retrieve a consumer based on the User-Agent
98
anonymous_request = True
99
consumer_key = request.getHeader('User-Agent', '')
100
if consumer_key == '':
102
'Anonymous requests must provide a User-Agent.')
103
consumer = consumers.getByKey(consumer_key)
106
if anonymous_request:
107
# This is the first time anyone has tried to make an
108
# anonymous request using this consumer name (or user
109
# agent). Dynamically create the consumer.
111
# In the normal website this wouldn't be possible
112
# because GET requests have their transactions rolled
113
# back. But webservice requests always have their
114
# transactions committed so that we can keep track of
115
# the OAuth nonces and prevent replay attacks.
116
if consumer_key == '' or consumer_key is None:
117
raise Unauthorized("No consumer key specified.")
118
consumer = consumers.new(consumer_key, '')
120
# An unknown consumer can never make a non-anonymous
121
# request, because access tokens are registered with a
122
# specific, known consumer.
123
raise Unauthorized('Unknown consumer (%s).' % consumer_key)
124
if anonymous_request:
125
# Skip the OAuth verification step and let the user access the
126
# web service as an unauthenticated user.
128
# XXX leonardr 2009-12-15 bug=496964: Ideally we'd be
129
# auto-creating a token for the anonymous user the first
130
# time, passing it through the OAuth verification step,
131
# and using it on all subsequent anonymous requests.
134
token = consumer.getAccessToken(token_key)
136
raise Unauthorized('Unknown access token (%s).' % token_key)
140
def get_oauth_principal(request):
141
"""Find the principal to use for this OAuth-signed request.
143
:param request: An incoming request.
144
:return: An ILaunchpadPrincipal with the appropriate access level.
146
token = extract_oauth_access_token(request)
149
# The consumer is making an anonymous request. If there was a
150
# problem with the access token, extract_oauth_access_token
151
# would have raised Unauthorized.
152
alsoProvides(request, IOAuthSignedRequest)
153
auth_utility = getUtility(IPlacelessAuthUtility)
154
return auth_utility.unauthenticatedPrincipal()
156
form = get_oauth_authorization(request)
157
nonce = form.get('oauth_nonce')
158
timestamp = form.get('oauth_timestamp')
160
token.checkNonceAndTimestamp(nonce, timestamp)
161
except (NonceAlreadyUsed, TimestampOrderingError, ClockSkew), e:
162
raise Unauthorized('Invalid nonce/timestamp: %s' % e)
163
now = datetime.now(pytz.timezone('UTC'))
164
if token.permission == OAuthPermission.UNAUTHORIZED:
165
raise Unauthorized('Unauthorized token (%s).' % token.key)
166
elif token.date_expires is not None and token.date_expires <= now:
167
raise Unauthorized('Expired token (%s).' % token.key)
168
elif not check_oauth_signature(request, token.consumer, token):
169
raise Unauthorized('Invalid signature.')
171
# Everything is fine, let's return the principal.
173
alsoProvides(request, IOAuthSignedRequest)
174
return getUtility(IPlacelessLoginSource).getPrincipal(
175
token.person.account.id, access_level=token.permission,
179
54
class PlacelessAuthUtility:
180
55
"""An authentication service which holds no state aside from its
181
56
ZCML configuration, implemented as a utility.