def get_user_app_info(request): try: oauth_request = OAUTH_SERVER.extract_oauth_request(djangoutils.extract_request(request)) consumer, token, parameters = OAUTH_SERVER.check_resource_access(oauth_request) return consumer, token, parameters, oauth_request except oauth.OAuthError: return None, None, None, None
def get_user_app_info(request): try: oauth_request = OAUTH_SERVER.extract_oauth_request( djangoutils.extract_request(request)) consumer, token, parameters = OAUTH_SERVER.check_resource_access( oauth_request) return consumer, token, parameters, oauth_request except oauth.OAuthError: return None, None, None, None
def record_pha_setup(request, record, pha): """Set up a PHA in a record ahead of time FIXME: eventually, when there are permission restrictions on a PHA, make sure that any permission restrictions on the current PHA are transitioned accordingly """ content = request.raw_post_data # if there is a document, create it if content: # is there already a setup doc setup_docs = Document.objects.filter(record=record, pha=pha, external_id='SETUP') if len(setup_docs) == 0: new_doc = _document_create( record = record, creator = request.principal, pha = pha, content = content, external_id = Document.prepare_external_id('SETUP', pha, pha_specific=True, record_specific=True)) # preauthorize the token. from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.generate_and_preauthorize_access_token(pha, record=record) # return the token return HttpResponse(access_token.to_string(), mimetype="application/x-www-form-urlencoded")
def request_token(request): """ Get a new request token, bound to a record or carenet if desired. request.POST may contain **EITHER**: * *indivo_record_id*: The record to which to bind the request token. * *indivo_carenet_id*: The carenet to which to bind the request token. Will return :http:statuscode:`200` with the request token on success, :http:statuscode:`403` if the oauth signature on the request was missing or faulty. """ # ask the oauth server to generate a request token given the HTTP request try: # we already have the oauth_request in context, so we don't get it again from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.generate_request_token( request.oauth_request, record_id=request.POST.get("indivo_record_id", None), carenet_id=request.POST.get("indivo_carenet_id", None), ) return HttpResponse(request_token.to_string(), mimetype="text/plain") except oauth.OAuthError, e: # an exception can be raised if there is a bad signature (or no signature) in the request raise PermissionDenied()
def request_token_approve(request, reqtoken): record_id = request.POST.get('record_id', None) carenet_id = request.POST.get('carenet_id', None) record = None if record_id: record = Record.objects.get(id = record_id) carenet = None if carenet_id: carenet = Carenet.objects.get(id = carenet_id) # if the request token was bound to a record, then it must match if reqtoken.record != None and reqtoken.record != record: raise PermissionDenied() # if the request token was bound to a carenet if reqtoken.carenet != None and reqtoken.carenet != carenet: raise PermissionDenied() # the permission check that the current user is authorized to connect to this record # or to this carenet is already done in accesscontrol # authorize the request token from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.authorize_request_token(reqtoken.token, record = record, carenet = carenet, account = request.principal) # where to redirect to + parameters redirect_url = request_token.oauth_callback or request_token.pha.callback_url redirect_url += "?oauth_token=%s&oauth_verifier=%s" % (request_token.token, request_token.verifier) # redirect to the request token's callback, or if null the PHA's default callback return HttpResponse(urllib.urlencode({'location': redirect_url}))
def request_token(request): """ Get a new request token, bound to a record or carenet if desired. request.POST may contain **EITHER**: * *indivo_record_id*: The record to which to bind the request token. * *indivo_carenet_id*: The carenet to which to bind the request token. Will return :http:statuscode:`200` with the request token on success, :http:statuscode:`403` if the oauth signature on the request was missing or faulty. """ # ask the oauth server to generate a request token given the HTTP request try: # we already have the oauth_request in context, so we don't get it again from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.generate_request_token(request.oauth_request, record_id = request.POST.get('indivo_record_id', None), carenet_id = request.POST.get('indivo_carenet_id', None)) return HttpResponse(request_token.to_string(), mimetype='text/plain') except oauth.OAuthError, e: # an exception can be raised if there is a bad signature (or no signature) in the request raise PermissionDenied()
def exchange_token(request): # ask the oauth server to exchange a request token into an access token # this will check proper oauth for this action try: access_token = OAUTH_SERVER.exchange_request_token(request.oauth_request) # an exception can be raised if there is a bad signature (or no signature) in the request except: raise PermissionDenied() return HttpResponse(access_token.to_string(), mimetype="text/plain")
def request_token_approve(request, reqtoken): """ Indicate a user's consent to bind an app to a record or carenet. request.POST must contain **EITHER**: * *record_id*: The record to bind to. * *carenet_id*: The carenet to bind to. Will return :http:statuscode:`200` with a redirect url to the app on success, :http:statuscode:`403` if *record_id*/*carenet_id* don't match *reqtoken*. """ record_id = request.POST.get('record_id', None) carenet_id = request.POST.get('carenet_id', None) record = None if record_id: record = Record.objects.get(id=record_id) carenet = None if carenet_id: carenet = Carenet.objects.get(id=carenet_id) # if the request token was bound to a record, then it must match if reqtoken.record != None and reqtoken.record != record: raise PermissionDenied() # if the request token was bound to a carenet if reqtoken.carenet != None and reqtoken.carenet != carenet: raise PermissionDenied() # the permission check that the current user is authorized to connect to this record # or to this carenet is already done in accesscontrol # authorize the request token from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.authorize_request_token( reqtoken.token, record=record, carenet=carenet, account=request.principal) # where to redirect to + parameters redirect_url = request_token.oauth_callback or request_token.pha.callback_url redirect_url += "?oauth_token=%s&oauth_verifier=%s" % ( request_token.token, request_token.verifier) # redirect to the request token's callback, or if null the PHA's default callback return HttpResponse(urllib.urlencode({'location': redirect_url}))
def request_token(request): """ the request-token request URL """ # ask the oauth server to generate a request token given the HTTP request try: # we already have the oauth_request in context, so we don't get it again request_token = OAUTH_SERVER.generate_request_token(request.oauth_request, record_id = request.POST.get('indivo_record_id', None), carenet_id = request.POST.get('indivo_carenet_id', None)) return HttpResponse(request_token.to_string(), mimetype='text/plain') except oauth.OAuthError, e: # an exception can be raised if there is a bad signature (or no signature) in the request raise PermissionDenied()
def request_token_approve(request, reqtoken): """ Indicate a user's consent to bind an app to a record or carenet. request.POST must contain **EITHER**: * *record_id*: The record to bind to. * *carenet_id*: The carenet to bind to. Will return :http:statuscode:`200` with a redirect url to the app on success, :http:statuscode:`403` if *record_id*/*carenet_id* don't match *reqtoken*. """ record_id = request.POST.get("record_id", None) carenet_id = request.POST.get("carenet_id", None) record = None if record_id: record = Record.objects.get(id=record_id) carenet = None if carenet_id: carenet = Carenet.objects.get(id=carenet_id) # if the request token was bound to a record, then it must match if reqtoken.record != None and reqtoken.record != record: raise PermissionDenied() # if the request token was bound to a carenet if reqtoken.carenet != None and reqtoken.carenet != carenet: raise PermissionDenied() # the permission check that the current user is authorized to connect to this record # or to this carenet is already done in accesscontrol # authorize the request token from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.authorize_request_token( reqtoken.token, record=record, carenet=carenet, account=request.principal ) # where to redirect to + parameters redirect_url = request_token.oauth_callback or request_token.pha.callback_url redirect_url += "?oauth_token=%s&oauth_verifier=%s" % (request_token.token, request_token.verifier) # redirect to the request token's callback, or if null the PHA's default callback return HttpResponse(urllib.urlencode({"location": redirect_url}))
def record_pha_setup(request, record, pha): """ Bind an app to a record without user authorization. This call should be used to set up new records with apps required for this instance of Indivo to run (i.e. syncer apps that connect to data sources). It can only be made by admins, since it skips the normal app authorization process. ``request.POST`` may contain raw content that will be used as a setup document for the record. Will return :http:statuscode:`200` with a valid access token for the app bound to the record on success. """ # TODO: eventually, when there are permission restrictions on a PHA, # make sure that any permission restrictions on the current PHA are # transitioned accordingly. content = request.raw_post_data # if there is a document, create it if content: # is there already a setup doc setup_docs = Document.objects.filter(record=record, pha=pha, external_id='SETUP') if len(setup_docs) == 0: new_doc = _document_create( record=record, creator=request.principal, pha=pha, content=content, external_id=Document.prepare_external_id('SETUP', pha, pha_specific=True, record_specific=True)) # preauthorize the token. from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.generate_and_preauthorize_access_token( pha, record=record) # return the token return HttpResponse(access_token.to_string(), mimetype="application/x-www-form-urlencoded")
def autonomous_access_token(request, pha, record): """ Fetch an access token for an autonomous app to access a record. This call *assumes* that the app has already been enabled on the record, and that the user has already authorized it (this must be checked in the access control for the function). Otherwise, this will automatically enable the app on the record (a BAD idea). This call should be made by autonomous apps to get access tokens for records which have already enabled them (presumably after a call to app_record_list). Will return :http:statuscode:`200` with a valid access token for the app bound to the record on success. """ from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.generate_and_preauthorize_access_token(pha, record=record) return HttpResponse(access_token.to_string(), mimetype="application/x-www-form-urlencoded")
def record_pha_setup(request, record, pha): """ Bind an app to a record without user authorization. This call should be used to set up new records with apps required for this instance of Indivo to run (i.e. syncer apps that connect to data sources). It can only be made by admins, since it skips the normal app authorization process. ``request.POST`` may contain raw content that will be used as a setup document for the record. Will return :http:statuscode:`200` with a valid access token for the app bound to the record on success. """ # TODO: eventually, when there are permission restrictions on a PHA, # make sure that any permission restrictions on the current PHA are # transitioned accordingly. content = request.raw_post_data # if there is a document, create it if content: # is there already a setup doc setup_docs = Document.objects.filter(record=record, pha=pha, external_id="SETUP") if len(setup_docs) == 0: new_doc = _document_create( record=record, creator=request.principal, pha=pha, content=content, external_id=Document.prepare_external_id("SETUP", pha, pha_specific=True, record_specific=True), ) # preauthorize the token. from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.generate_and_preauthorize_access_token(pha, record=record) # return the token return HttpResponse(access_token.to_string(), mimetype="application/x-www-form-urlencoded")
def autonomous_access_token(request, pha, record): """ Fetch an access token for an autonomous app to access a record. This call *assumes* that the app has already been enabled on the record, and that the user has already authorized it (this must be checked in the access control for the function). Otherwise, this will automatically enable the app on the record (a BAD idea). This call should be made by autonomous apps to get access tokens for records which have already enabled them (presumably after a call to app_record_list). Will return :http:statuscode:`200` with a valid access token for the app bound to the record on success. """ from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.generate_and_preauthorize_access_token( pha, record=record) return HttpResponse(access_token.to_string(), mimetype="application/x-www-form-urlencoded")
def exchange_token(request): """ Exchange a request token for a valid access token. This call requires that the request be signed with a valid oauth request token that has previously been authorized. Will return :http:statuscode:`200` with the access token on success, :http:statuscode:`403` if the oauth signature is missing or invalid. """ # ask the oauth server to exchange a request token into an access token # this will check proper oauth for this action try: from indivo.accesscontrol.oauth_servers import OAUTH_SERVER access_token = OAUTH_SERVER.exchange_request_token(request.oauth_request) # an exception can be raised if there is a bad signature (or no signature) in the request except: raise PermissionDenied() return HttpResponse(access_token.to_string(), mimetype='text/plain')
def user_authorization(request): """Authorize a request token, binding it to a single record. A request token *must* be bound to a record before it is approved. """ try: token = ReqToken.objects.get(token = request.REQUEST['oauth_token']) except ReqToken.DoesNotExist: raise Http404 # are we processing the form # OR, is this app already authorized if request.method == "POST" or (token.record and token.record.has_pha(token.pha)): # get the record from the token record = token.record # are we dealing with a record already if not (record and record.has_pha(token.pha)): record = Record.objects.get(id = request.POST['record_id']) # allowed to administer the record? Needed if the record doesn't have the PHA yet if not record.can_admin(request.principal): raise Exception("cannot administer this record") from indivo.accesscontrol.oauth_servers import OAUTH_SERVER request_token = OAUTH_SERVER.authorize_request_token(token.token, record = record, account = request.principal) # where to redirect to + parameters redirect_url = request_token.oauth_callback or request_token.pha.callback_url redirect_url += "?oauth_token=%s&oauth_verifier=%s" % (request_token.token, request_token.verifier) # redirect to the request token's callback, or if null the PHA's default callback return HttpResponseRedirect(redirect_url) else: records = request.principal.records_administered.all() return render_template('authorize', {'token' : token, 'records': records})
def get_connect_credentials(request, account, pha): """ Get oAuth credentials for an app to run in Connect or SMART REST mode. Generates access tokens for *pha* to run against the *record_id* specified in ``request.POST``, authorized by *account*. Generates 2 tokens: one for SMART Connect use, and one for SMART REST use. If the app is not yet enabled for the record/carenet, this will return a :http:statuscode:`403`. """ carenet = record = None carenet_id = request.POST.get('carenet_id', None) record_id = request.POST.get('record_id', None) if carenet_id: try: carenet=Carenet.objects.get(id=carenet_id) except Carenet.DoesNotExist: raise Http404 except Carenet.MultipleObjectsReturned: raise Exception("Multiple carenets with same id--database is corrupt") elif record_id: try: record = Record.objects.get(id=record_id) except Record.DoesNotExist: raise Http404 except Record.MultipleObjectsReturned: raise Exception("Multiple records with same id--database is corrupt") # Make sure that the app is enabled if (record and not PHAShare.objects.filter(record=record, with_pha=pha).exists()) or \ (carenet and not CarenetPHA.objects.filter(carenet=carenet, pha=pha).exists()): raise PermissionDenied("Cannot generate credentials before app is enabled") # Generate the tokens from indivo.accesscontrol.oauth_servers import OAUTH_SERVER rest_token = OAUTH_SERVER.generate_and_preauthorize_access_token(pha, record=record, carenet=carenet, account=account) connect_token = OAUTH_SERVER.generate_and_preauthorize_access_token(pha, record=record, carenet=carenet, account=account) connect_token.connect_auth_p = True connect_token.save() # Generate a 2-legged oauth header for the rest token, based on the pha's start_url url = utils.url_interpolate(pha.start_url_template, {'record_id':record_id or '', 'carenet_id':carenet_id or ''}) request = HTTPRequest("GET", url, HTTPRequest.FORM_URLENCODED_TYPE, '', {}) oauth_params = { 'smart_container_api_base': settings.SITE_URL_PREFIX, 'smart_oauth_token': rest_token.token, 'smart_oauth_token_secret': rest_token.token_secret, 'smart_user_id': account.email, 'smart_app_id': pha.email, 'smart_record_id': record_id, } oauth_request = OAuthRequest(consumer=pha, token=None, # no access tokens: 2-legged request http_request=request, oauth_parameters=oauth_params) oauth_request.sign() auth_header = oauth_request.to_header()["Authorization"] return render_template('connect_credentials', { 'connect_token': connect_token, 'rest_token': rest_token, 'api_base': settings.SITE_URL_PREFIX, 'oauth_header': auth_header, 'app_email':pha.email}, type='xml')
def get_connect_credentials(request, account, pha): """ Get oAuth credentials for an app to run in Connect or SMART REST mode. Generates access tokens for *pha* to run against the *record_id* specified in ``request.POST``, authorized by *account*. Generates 2 tokens: one for SMART Connect use, and one for SMART REST use. If the app is not yet enabled for the record/carenet, this will return a :http:statuscode:`403`. """ carenet = record = None carenet_id = request.POST.get('carenet_id', None) record_id = request.POST.get('record_id', None) if carenet_id: try: carenet = Carenet.objects.get(id=carenet_id) except Carenet.DoesNotExist: raise Http404 except Carenet.MultipleObjectsReturned: raise Exception( "Multiple carenets with same id--database is corrupt") elif record_id: try: record = Record.objects.get(id=record_id) except Record.DoesNotExist: raise Http404 except Record.MultipleObjectsReturned: raise Exception( "Multiple records with same id--database is corrupt") # Make sure that the app is enabled if (record and not PHAShare.objects.filter(record=record, with_pha=pha).exists()) or \ (carenet and not CarenetPHA.objects.filter(carenet=carenet, pha=pha).exists()): raise PermissionDenied( "Cannot generate credentials before app is enabled") # Generate the tokens from indivo.accesscontrol.oauth_servers import OAUTH_SERVER rest_token = OAUTH_SERVER.generate_and_preauthorize_access_token( pha, record=record, carenet=carenet, account=account) connect_token = OAUTH_SERVER.generate_and_preauthorize_access_token( pha, record=record, carenet=carenet, account=account) connect_token.connect_auth_p = True connect_token.save() # Generate a 2-legged oauth header for the rest token, based on the pha's start_url url = utils.url_interpolate(pha.start_url_template, { 'record_id': record_id or '', 'carenet_id': carenet_id or '' }) request = HTTPRequest("GET", url, HTTPRequest.FORM_URLENCODED_TYPE, '', {}) oauth_params = { 'smart_container_api_base': settings.SITE_URL_PREFIX, 'smart_oauth_token': rest_token.token, 'smart_oauth_token_secret': rest_token.token_secret, 'smart_user_id': account.email, 'smart_app_id': pha.email, 'smart_record_id': record_id, } oauth_request = OAuthRequest( consumer=pha, token=None, # no access tokens: 2-legged request http_request=request, oauth_parameters=oauth_params) oauth_request.sign() auth_header = oauth_request.to_header()["Authorization"] return render_template('connect_credentials', { 'connect_token': connect_token, 'rest_token': rest_token, 'api_base': settings.SITE_URL_PREFIX, 'oauth_header': auth_header, 'app_email': pha.email }, type='xml')