Advertisement
Guest User

Untitled

a guest
Jan 28th, 2018
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.38 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. from __future__ import print_function
  3. import sys
  4. import os
  5. sys.path.append("lib")
  6. import jwt
  7. import re
  8. import json
  9. import datetime, time
  10.  
  11. def login(event, context):
  12.     try:
  13.         body = json.loads(event['body'])
  14.         username = body['username']
  15.         password = body['password']
  16.         secret = os.environ.get('APIKEY')
  17.         ttl = int(os.environ.get('TTLJWT'))
  18.         ## CHECK LOGIN IN DATABASE HERE
  19.         ##
  20.         userid = 287038
  21.         dts = datetime.datetime.utcnow()
  22.         epochtime = round(time.mktime(dts.timetuple()) + dts.microsecond/1e6)
  23.         encobject = {'id': userid,'name':username,"iat":epochtime,"exp":epochtime+ttl}
  24.         encoded = jwt.encode(encobject, secret, algorithm='HS256')
  25.         body = {"token": encoded}
  26.         response = {"statusCode": 200,"body": json.dumps(body)}
  27.     except:
  28.         body = {}
  29.         response = {"statusCode": 401,"body": json.dumps(body)}
  30.  
  31.     return response
  32. def authorizer(event, context):
  33.     try:
  34.         token = event['authorizationToken']
  35.         secret = os.environ.get('APIKEY')
  36.         ttl = int(os.environ.get('TTLJWT'))
  37.         decoded = jwt.decode(token, secret, algorithms=['HS256'])
  38.         #If we are here, decode was complete
  39.         principalId = decoded["id"]
  40.         uid = int(decoded["id"])
  41.         dts = datetime.datetime.utcnow()
  42.         epochtime = round(time.mktime(dts.timetuple()) + dts.microsecond/1e6)
  43.         if epochtime > decoded["exp"] or decoded["exp"]-decoded["iat"]!=ttl:
  44.             raise Exception('Unauthorized')
  45.         tmp = event['methodArn'].split(':')
  46.         apiGatewayArnTmp = tmp[5].split('/')
  47.         awsAccountId = tmp[4]
  48.         policy = AuthPolicy(principalId, awsAccountId)
  49.         policy.restApiId = apiGatewayArnTmp[0]
  50.         policy.region = tmp[3]
  51.         policy.stage = apiGatewayArnTmp[1]
  52.         policy.allowAllMethods()
  53.         """policy.allowMethod(HttpVerb.GET, "/pets/*")"""
  54.  
  55.         # Finally, build the policy
  56.         authResponse = policy.build()
  57.  
  58.         # new! -- add additional key-value pairs associated with the authenticated principal
  59.         # these are made available by APIGW like so: $context.authorizer.<key>
  60.         # additional context is cached
  61.         #context = {
  62.         #    'key': 'value', # $context.authorizer.key -> value
  63.         #    'number' : 1,
  64.         #    'bool' : True
  65.         #}
  66.         context = {}
  67.         # context['arr'] = ['foo'] <- this is invalid, APIGW will not accept it
  68.         # context['obj'] = {'foo':'bar'} <- also invalid
  69.         authResponse['context'] = context
  70.         return authResponse
  71.     except:
  72.         raise Exception('Unauthorized')
  73.  
  74.  
  75. class HttpVerb:
  76.     GET     = "GET"
  77.     POST    = "POST"
  78.     PUT     = "PUT"
  79.     PATCH   = "PATCH"
  80.     HEAD    = "HEAD"
  81.     DELETE  = "DELETE"
  82.     OPTIONS = "OPTIONS"
  83.     ALL     = "*"
  84.  
  85. class AuthPolicy(object):
  86.     awsAccountId = ""
  87.     """The AWS account id the policy will be generated for. This is used to create the method ARNs."""
  88.     principalId = ""
  89.     """The principal used for the policy, this should be a unique identifier for the end user."""
  90.     version = "2012-10-17"
  91.     """The policy version used for the evaluation. This should always be '2012-10-17'"""
  92.     pathRegex = "^[/.a-zA-Z0-9-\*]+$"
  93.     """The regular expression used to validate resource paths for the policy"""
  94.  
  95.     """these are the internal lists of allowed and denied methods. These are lists
  96.    of objects and each object has 2 properties: A resource ARN and a nullable
  97.    conditions statement.
  98.    the build method processes these lists and generates the approriate
  99.    statements for the final policy"""
  100.     allowMethods = []
  101.     denyMethods = []
  102.  
  103.     restApiId = "*"
  104.     """The API Gateway API id. By default this is set to '*'"""
  105.     region = "*"
  106.     """The region where the API is deployed. By default this is set to '*'"""
  107.     stage = "*"
  108.     """The name of the stage used in the policy. By default this is set to '*'"""
  109.  
  110.     def __init__(self, principal, awsAccountId):
  111.         self.awsAccountId = awsAccountId
  112.         self.principalId = principal
  113.         self.allowMethods = []
  114.         self.denyMethods = []
  115.  
  116.     def _addMethod(self, effect, verb, resource, conditions):
  117.         """Adds a method to the internal lists of allowed or denied methods. Each object in
  118.        the internal list contains a resource ARN and a condition statement. The condition
  119.        statement can be null."""
  120.         if verb != "*" and not hasattr(HttpVerb, verb):
  121.             raise NameError("Invalid HTTP verb " + verb + ". Allowed verbs in HttpVerb class")
  122.         resourcePattern = re.compile(self.pathRegex)
  123.         if not resourcePattern.match(resource):
  124.             raise NameError("Invalid resource path: " + resource + ". Path should match " + self.pathRegex)
  125.  
  126.         if resource[:1] == "/":
  127.             resource = resource[1:]
  128.  
  129.         resourceArn = ("arn:aws:execute-api:" +
  130.             self.region + ":" +
  131.             self.awsAccountId + ":" +
  132.             self.restApiId + "/" +
  133.             self.stage + "/" +
  134.             verb + "/" +
  135.             resource)
  136.  
  137.         if effect.lower() == "allow":
  138.             self.allowMethods.append({
  139.                 'resourceArn' : resourceArn,
  140.                 'conditions' : conditions
  141.             })
  142.         elif effect.lower() == "deny":
  143.             self.denyMethods.append({
  144.                 'resourceArn' : resourceArn,
  145.                 'conditions' : conditions
  146.             })
  147.  
  148.     def _getEmptyStatement(self, effect):
  149.         """Returns an empty statement object prepopulated with the correct action and the
  150.        desired effect."""
  151.         statement = {
  152.             'Action': 'execute-api:Invoke',
  153.             'Effect': effect[:1].upper() + effect[1:].lower(),
  154.             'Resource': []
  155.         }
  156.  
  157.         return statement
  158.  
  159.     def _getStatementForEffect(self, effect, methods):
  160.         """This function loops over an array of objects containing a resourceArn and
  161.        conditions statement and generates the array of statements for the policy."""
  162.         statements = []
  163.  
  164.         if len(methods) > 0:
  165.             statement = self._getEmptyStatement(effect)
  166.  
  167.             for curMethod in methods:
  168.                 if curMethod['conditions'] is None or len(curMethod['conditions']) == 0:
  169.                     statement['Resource'].append(curMethod['resourceArn'])
  170.                 else:
  171.                     conditionalStatement = self._getEmptyStatement(effect)
  172.                     conditionalStatement['Resource'].append(curMethod['resourceArn'])
  173.                     conditionalStatement['Condition'] = curMethod['conditions']
  174.                     statements.append(conditionalStatement)
  175.  
  176.             statements.append(statement)
  177.  
  178.         return statements
  179.  
  180.     def allowAllMethods(self):
  181.         """Adds a '*' allow to the policy to authorize access to all methods of an API"""
  182.         self._addMethod("Allow", HttpVerb.ALL, "*", [])
  183.  
  184.     def denyAllMethods(self):
  185.         """Adds a '*' allow to the policy to deny access to all methods of an API"""
  186.         self._addMethod("Deny", HttpVerb.ALL, "*", [])
  187.  
  188.     def allowMethod(self, verb, resource):
  189.         """Adds an API Gateway method (Http verb + Resource path) to the list of allowed
  190.        methods for the policy"""
  191.         self._addMethod("Allow", verb, resource, [])
  192.  
  193.     def denyMethod(self, verb, resource):
  194.         """Adds an API Gateway method (Http verb + Resource path) to the list of denied
  195.        methods for the policy"""
  196.         self._addMethod("Deny", verb, resource, [])
  197.  
  198.     def allowMethodWithConditions(self, verb, resource, conditions):
  199.         """Adds an API Gateway method (Http verb + Resource path) to the list of allowed
  200.        methods and includes a condition for the policy statement. More on AWS policy
  201.        conditions here: http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition"""
  202.         self._addMethod("Allow", verb, resource, conditions)
  203.  
  204.     def denyMethodWithConditions(self, verb, resource, conditions):
  205.         """Adds an API Gateway method (Http verb + Resource path) to the list of denied
  206.        methods and includes a condition for the policy statement. More on AWS policy
  207.        conditions here: http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition"""
  208.         self._addMethod("Deny", verb, resource, conditions)
  209.  
  210.     def build(self):
  211.         """Generates the policy document based on the internal lists of allowed and denied
  212.        conditions. This will generate a policy with two main statements for the effect:
  213.        one statement for Allow and one statement for Deny.
  214.        Methods that includes conditions will have their own statement in the policy."""
  215.         if ((self.allowMethods is None or len(self.allowMethods) == 0) and
  216.             (self.denyMethods is None or len(self.denyMethods) == 0)):
  217.             raise NameError("No statements defined for the policy")
  218.  
  219.         policy = {
  220.             'principalId' : self.principalId,
  221.             'policyDocument' : {
  222.                 'Version' : self.version,
  223.                 'Statement' : []
  224.             }
  225.         }
  226.  
  227.         policy['policyDocument']['Statement'].extend(self._getStatementForEffect("Allow", self.allowMethods))
  228.         policy['policyDocument']['Statement'].extend(self._getStatementForEffect("Deny", self.denyMethods))
  229.  
  230.         return policy
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement