/usr/lib/falcon/web/oauth.fal is in libfalcon-engine1 0.9.6.9-git20120606-2.1+b1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | /*
FALCON - The Falcon Programming Language.
OAuth authentication scheme support - main file
FILE: oauth.fal
Main module file
-------------------------------------------------------------------
Author: Giancarlo Niccolai
Begin: Mon, 21 Jun 2010 13:38:47 +0200
-------------------------------------------------------------------
(C) Copyright 2010: the FALCON developers (see list in AUTHORS file)
See LICENSE file for licensing details.
*/
import from hash
import from curl
/*#
@main Support for OAuth 1.0 protocol.
This modules code to establish OAuth sessions.
OAuth is a cross-site authentication exchange protocol
used in Web2.0 development.
@note The module depends on Feathers @a hash module and on
the optional @a curl module.
*/
const OAUTH_REQ_PREFIX = "OAUTH-REQ-"
//# Enumeration used as OAUTH connection method.
enum Via
//# Use Post method
POST = "POST"
//# Use Get method
GET = "GET"
end
//# Enumeration used to determine if the Authorization header should be used or not.
enum UseHeader
//# Do not use the Authorization header in request.
NONE
//# Send the oauth_* parameters in the header and the rest via the standard method.
ALTERN
//# Send the oauth_* parameters in the header, but send them via the standard request.
FULL
end
/*# Error raised from OAuth in case of protocol breach.
@param code Code of the error
@param desc Description of the error
@param extra Error condition or specific description.
*/
class ProtoError( code, desc, extra ) from Error( code, desc, extra )
end
/*# Class representing an OAuth token.
@param token OAuth authorization token.
@param secret Secret data used to sign the request.
Oauth steps
*/
class Token( token, secret )
//# Token ID (empty for initial request-token queries).
token = token
//# Signature key associated with this token
secret = secret
//# Validator field returned by the remote server
verifier = nil
//# full data returned by the remote server.
raw_data = nil
//# true if the token has been authorized
authorized = false
//# true if this token has been exchanged.
exchanged = false
/*# Check if this token is a request token.
@return true if this is a valid request token.
*/
function isRequest(): return self.token and not self.exchanged
/*# Check if this token is an access token.
@return true if this is a valid access token.
*/
function isAccess(): return self.exchanged
// Gets extra data returned in the raw data. TODO
function getExtraData()
ret = [=>]
for k,v in self.raw_data
if not k.startsWith( "oauth_" )
ret[k] = v
end
end
return ret
end
end
/*# Interface to remote OAuth authentication process server.
@param cust_id The consumer key identifying the requester on the remote OAuth server.
@param cust_secret The consumer secret used to sign OAuth requests.
@optparam mode One of the @a Via methods (Defaults to POST).
This class acts as an authentication client connecting with a
remote server.
*/
class Client( cust_id, cust_secret, mode )
//# Customer id associated with this client
cust_id = cust_id
//# Secret data used to countersign requests for this client
secret = cust_secret
//# connection mode (one of the @a Via methods)
mode = mode ? mode : Via.POST
/*# Should we use the header field?
Should be one of the @a UseHeader enumeration values.
If @b UseHeader.NONE, the Authorization header field is never sent.
If @b UseHeader.ALTERN, the OAuth fields are MOVED in the header, and the
selected mode ("GET" or "POST") is used @b only to send the non-oauth parameters.
If @b UseHeader.FULL, the OAuth fields are copied in the Authorization header,
but they are sent also via the POST or GET query string.
*/
use_header = UseHeader.NONE
//# @ignore
signature_method = "HMAC-SHA1"
//# OAuth protocol version. Defaults to 1.0
version = "1.0"
/*# Perform a token request.
@param address The address of the remote token provider.
@optparam callback Address to be called back by authenticator if the caller is of a web application.
@optparam token An instance of the Token class to be exchanged token exchange.
@return A new @a Token created through this call.
@raise ProtoError if the remote side doesn't complain with the OAuth protocol.
This method requests a "Request token" or an "Access token" the remote OAuth service.
Initially, the caller must create a request token by calling this method; on success,
a valid (but not yet authorized) request token is returned.
Once this token is authorized through other means (i.e. redirecting the user to the
remote service site), it can be exchanged with an access token calling this method
and passing the previously returned token. The request token is discarded and the parameter becomes
an access token, that can then be used to access reserved resources (via the @a callAPI method).
For example, a theoretic workflow may be
@code
import from web.oauth in oauth
client = oauth.Client( "MyClientID", "MyClientSecret" )
req_token = client.getToken( "https://TheRemoteService/get_req_token" )
//...
// authorize the token
//...
access_token = client.getToken( "https://TheRemoteService/login", nil, req_token )
userData = client.callAPI( access_token,
"https://TheRemoteService/get_user",
["user_id"=> my_user_id] )
@endcode
@note This method blocks until the remote side replies.
*/
function getToken( address, callback, token )
params = self._makeBaseParams()
if token
params[ "oauth_token" ] = token.token
tsecret = token.secret
if token.verifier
params["oauth_verifier"] = token.verifier
end
end
if callback: params[ "oauth_callback" ] = callback
cr = self.makeOAuthHandler( address, tsecret, params, nil )
cr.setOutString()
cr.exec()
data = cr.getData()
try
dt = self.parseQS( data )
catch ParamError
raise ProtoError( 10001, i"Invalid answer from remote.", data )
end
if not "oauth_token" in dt
raise ProtoError( 10002, i"Response didn't contain an oauth_token", data )
end
if not "oauth_token_secret" in dt
raise ProtoError( 10003, i"Response didn't contain an oauth_token_secret", data )
end
token = Token( dt["oauth_token"], dt["oauth_token_secret"] )
token.raw_data = dt
if "oauth_verifier" in dt
token.validator = dt["oauth_verifier"]
end
return token
end
/*# Signature key-string generator.
@param cust_secret The customer signature part.
@optparam token_secret The part of the secret associated with a token.
The OAuth protocol doesn't dictate exactly the way in which
authorization strings must be signed, but in cases where counter-signature
is required, it mandates that both the customer secret and the token secret
must be used.
The most common way to counter-sign the authorization string is to concatenate
them through a "&" character, which is what this method does.
In case different OAuth applications requires different conuter-signature
strategies, this method can be overridden by subclasses.
*/
function makeSecret( cust_secret, token_secret )
if token_secret
return cust_secret + "&" + token_secret
else
return cust_secret + "&"
end
end
//==========================================================
// API utilities
//==========================================================
/*# Call an API protected by OAuth.
@param token An instance of @a Token.
@param uri The URI of the remote OAuth protected Web API to be called.
@optparam params Optional parameters for the call.
@return The raw data returned by the remote OAuth procedure.
Calls a remote web API and blocks until a result is available.
*/
function callAPI( token, uri, params )
oauth_params = self._makeBaseParams()
oauth_params["oauth_token"] = token.token
cr = self.makeOAuthHandler( uri, token.secret, oauth_params, params )
cr.setOutString()
cr.exec()
return cr.getData()
end
//# @ignore
function makeOAuthHandler( address, tsecret, oauth_params, params )
// Create the base string.
if params
all_params = oauth_params + params
else
all_params = oauth_params
end
base_fields = self._makeGet( all_params )
bstr = self._makeBaseString( self.mode, address, base_fields )
secret = self.makeSecret( self.secret, tsecret )
oauth_signature = Base64.encode( hash.hmac( true, hash.SHA1Hash, secret, bstr ) )
// Add the signature to the fields.
oauth_params["oauth_signature"] = oauth_signature
all_params["oauth_signature"] = oauth_signature
// Prepare the Authorization header.
if self.use_header == UseHeader.ALTERN
// In use header mode, send OAuth parameters via header.
query_string = self._makeGet( params )
headers = ["Authorization: OAuth realm=\"" +address+"\","+ self._makeAuthHeader( oauth_params ) ]
elif self.use_header == UseHeader.FULL
// In use header mode, send OAuth parameters via header AND via query
query_string = self._makeGet( all_params )
headers = ["Authorization: OAuth realm=\"" +address+"\","+ self._makeAuthHeader( oauth_params ) ]
else
// Send oauth fields only via query
query_string = self._makeGet( all_params )
headers = []
end
if self.mode == Via.POST
cr = curl.Handle( address )
cr.postData( query_string )
headers += ["Content-type: application/x-www-form-urlencoded"]
else
cr = curl.Handle( address + (query_string ? ("?" + query_string) : "" ))
end
if headers: cr.setOption( curl.OPT.HTTPHEADER, headers )
cr.setOption( curl.OPT.SSL_VERIFYPEER, false )
//cr.setOption( curl.OPT.HEADER, true )
return cr
end
//==========================================================
// Generic utilities
//==========================================================
/*# Static utility to parse a query string into a dictionary of values.
@param data A query string
@return a dictionary of values.
Typically, the query string is a pair of "key=value" strings separated
by "&" valeus, and encoded as URI encoded values.
*/
function parseQS( data )
res = [=>]
for item in data.split("&")
v = item.split("=",2)
if v.len() == 1
res[v[0]] =""
else
res[v[0]] = URI.decode(v[1])
end
end
return res
end
function _makeBaseParams()
params = [
"oauth_consumer_key" => self.cust_id,
"oauth_signature_method" => self.signature_method,
"oauth_timestamp" => toString(epoch()),
"oauth_nonce" => self._randomString(25),
"oauth_version" => self.version
]
return params
end
function _makeBaseString( method, base_uri, fields )
return method + "&" + URI.encode( base_uri ) + "&" + URI.encode( fields )
end
function _makeAuthHeader( params )
str = ""
for key, val in params
str += URI.encode( key ) + "=\"" + URI.encode( val ) + "\""
formiddle: str += ","
end
return str
end
function _makeGet( params )
str = ""
for key, val in params
str += URI.encode( key ) + "=" + URI.encode(val) + ""
formiddle: str += "&"
end
return str
end
function _randomString( size )
s = " " * size
r = random(0,51)
rstep = random(1,351234)
for i in [0:size]
r = (r + rstep) % 51
rstep = (rstep*2) % 349 + 1
if r >= 26
s[i] = "a"/ (r-26)
else
s[i] = "A"/ r
end
end
return s
end
end
|