Is it possible to check if a particular AWS IAM key has permissions for a set of specific commands?
Essentially, is there an API for AWS's privacy simulator?
So far I've been using hacks, such as executing a command with incorrect parameters that utilizes the permission in question, and watching what response I get back.
Example:
# needed resource: 'elasticloadbalancer:SetLoadBalancerListenerSSLCertificate'
# Check:
try:
elb.set_listener_SSL_certificate(443, 'fake')
except BotoServerError as e:
if e.error_code == 'AccessDenied':
print ("You don't have access to "
"elasticloadbalancer:SetLoadBalancerListenerSSLCertificate")
This is obviously hacky. Ideally I'd have some function call like iam.check_against(resource) or something. Any suggestions?
See boto3's simulate_principal_policy.
I've made this function to test for permissions (you'll need to modify it slightly, as it's not completely self-contained):
from typing import Dict, List, Optional
def blocked(
actions: List[str],
resources: Optional[List[str]] = None,
context: Optional[Dict[str, List]] = None
) -> List[str]:
"""test whether IAM user is able to use specified AWS action(s)
Args:
actions (list): AWS action(s) to validate IAM user can use.
resources (list): Check if action(s) can be used on resource(s).
If None, action(s) must be usable on all resources ("*").
context (dict): Check if action(s) can be used with context(s).
If None, it is expected that no context restrictions were set.
Returns:
list: Actions denied by IAM due to insufficient permissions.
"""
if not actions:
return []
actions = list(set(actions))
if resources is None:
resources = ["*"]
_context: List[Dict] = [{}]
if context is not None:
# Convert context dict to list[dict] expected by ContextEntries.
_context = [{
'ContextKeyName': context_key,
'ContextKeyValues': [str(val) for val in context_values],
'ContextKeyType': "string"
} for context_key, context_values in context.items()]
# You'll need to create an IAM client here
results = aws.iam_client().simulate_principal_policy(
PolicySourceArn=consts.IAM_ARN, # Your IAM user's ARN goes here
ActionNames=actions,
ResourceArns=resources,
ContextEntries=_context
)['EvaluationResults']
return sorted([result['EvalActionName'] for result in results
if result['EvalDecision'] != "allowed"])
You need to pass the permission's original action names to actions, like so:
blocked_actions = verify_perms.blocked(actions=[
"iam:ListUsers",
"iam:ListAccessKeys",
"iam:DeleteAccessKey",
"iam:ListGroupsForUser",
"iam:RemoveUserFromGroup",
"iam:DeleteUser"
])
Here's an example that uses the resources and context arguments as well:
def validate_type_and_size_allowed(instance_type, volume_size):
"""validate user is allowed to create instance with type and size"""
if validate_perms.blocked(actions=["ec2:RunInstances"],
resources=["arn:aws:ec2:*:*:instance/*"],
context={'ec2:InstanceType': [instance_type]}):
halt.err(f"Instance type {instance_type} not permitted.")
if validate_perms.blocked(actions=["ec2:RunInstances"],
resources=["arn:aws:ec2:*:*:volume/*"],
context={'ec2:VolumeSize': [volume_size]}):
halt.err(f"Volume size {volume_size}GiB is too large.")
The IAM Policy Simulator provides an excellent UI for determining which users have access to particular API calls.
If you wish to test this programmatically, use the DryRun parameter to make an API call. The function will not actually execute, but you will be informed whether it has sufficient permissions to execute. It will not, however, check whether the call itself would have succeeded (eg having an incorrect certificate name).
Related
I'm trying to see if an asset has been opted-in by a user on his wallet before performing a transfer of the asset to the user, but I can't seem to find how this is done in the Python algosdk. Any lead would be appreciated.
I expect to be able to call a function that verify if the asset had been opted-in to, or at least a list of all the opted-in assets, so I can check if the asset index is present in the list.
The list of assets that an account is opted in is provided by the /v2/account/{address} endpoint.
With the Python SDK, it is given by the account_information function of the V2 client.
Here is an example using the Algoexplorer TestNet API on the account GD7CZ4NH4PBZ75BSGBNXC76CYGEGEYVXYNGVNNWOYY33S64NV7VEISFGKE that is opted in asset ID 10458941 but not in asset ID 10 (at least when the post was written):
import algosdk.v2client
algod_address = "https://node.testnet.algoexplorerapi.io"
algod_token = ""
client = algosdk.v2client.algod.AlgodClient(algod_token, algod_address)
account = client.account_info("GD7CZ4NH4PBZ75BSGBNXC76CYGEGEYVXYNGVNNWOYY33S64NV7VEISFGKE")
def is_account_opted_in(account: dict, asset_id: int):
return any(asset["asset-id"] == asset_id for asset in account["assets"])
print(is_account_opted_in(account, 10458941))
print(is_account_opted_in(account, 10))
Flask-SSE doc --
https://flask-sse.readthedocs.io/en/latest/advanced.html#access-control
has a small Access Control example --
#sse.before_request
def check_access():
if request.args.get("channel") == "analytics" and not g.user.is_admin():
abort(403)
My use case is: I have two types of SSE endpoints, one type is public, say under route /sse/public/notice, which does not require authentication check; and also private ones with routes /sse/private/<user_id>/balance, which I must check both flask_login.current_user.is_authenticated and flask_login.current_user.get_id() == user_id
From Flask-SSE's simple example, I'm not sure how I can achieve supporting both types of sse endpoints.
Any pointer will be much appreciated.
I am the author of Flask-SSE. Why not do something like this?
#sse.before_request
def check_access():
channel = request.args.get("channel") or "sse"
if channel.startswith("private."):
if current_user.is_anonymous:
abort(401)
user_id = channel[8:]
if current_user.get_id() != user_id:
abort(403)
I would like to use the firebase database in my python program and restrict certain information to certain users. I have figured out how to set up the rules but would like to implement the authentication part into my program. I have imported:
from firebase import firebase
And I have a user: test.user#gmail.com pass: password123
how can would I make a post request that verifies that this user can indeed post?
You are able to create custom Security Rules and verify users permissions with Custom Claims.
Check this tutorial for more information
My solution was to first create a firestore "collection" keyed by user_id containing the claims. Then you can decorate your restricted methods to require a valid idToken plus arbitrary conditions on the claims:
import firebase_admin
import firebase_fave
# wrapper function to require credentials and claims!
def require_creds(creds_reqs={}):
def real_require_creds(protected_function):
#wraps(protected_function)
def protector(*args, **kwargs):
token = request.args.get('idToken', '')
try:
auth_resp = firebase_admin.auth.verify_id_token(token, check_revoked=True)
claims = firebase_admin.firestore.client().collection('user_claims')\
.document(auth_resp['user_id']).get().to_dict()
except:
abort(401)
if 'exp' in auth_resp\
and auth_resp['exp'] > time.time()\
and min(*[bool(creds_reqs[k](v)) for k, v in claims.items()]):
return protected_function(*args, **kwargs)
else:
abort(401)
return protector
return real_require_creds
Usage:
#require_creds(
{'access_flag': lambda x: x & 8, 'release_lag', lambda x: time.time() > RELEASE_TIME + x}
)
def your_post_method(self, ...
See also my monkey patch on pypi that adds a verify_user method to firebase_admin:
https://pypi.org/project/firebase_fave/
In order to test a Flask application, I got a flask test client POSTing request with files as attachment
def make_tst_client_service_call1(service_path, method, **kwargs):
_content_type = kwargs.get('content-type','multipart/form-data')
with app.test_client() as client:
return client.open(service_path, method=method,
content_type=_content_type, buffered=True,
follow_redirects=True,**kwargs)
def _publish_a_model(model_name, pom_env):
service_url = u'/publish/'
scc.data['modelname'] = model_name
scc.data['username'] = "BDD Script"
scc.data['instance'] = "BDD Stub Simulation"
scc.data['timestamp'] = datetime.now().strftime('%d-%m-%YT%H:%M')
scc.data['file'] = (open(file_path, 'rb'),file_name)
scc.response = make_tst_client_service_call1(service_url, method, data=scc.data)
Flask Server end point code which handles the above POST request is something like this
#app.route("/publish/", methods=['GET', 'POST'])
def publish():
if request.method == 'POST':
LOG.debug("Publish POST Service is called...")
upload_files = request.files.getlist("file[]")
print "Files :\n",request.files
print "Upload Files:\n",upload_files
return render_response_template()
I get this Output
Files:
ImmutableMultiDict([('file', <FileStorage: u'Single_XML.xml' ('application/xml')>)])
Upload Files:
[]
If I change
scc.data['file'] = (open(file_path, 'rb'),file_name)
into (thinking that it would handle multiple files)
scc.data['file'] = [(open(file_path, 'rb'),file_name),(open(file_path, 'rb'),file_name1)]
I still get similar Output:
Files:
ImmutableMultiDict([('file', <FileStorage: u'Single_XML.xml' ('application/xml')>), ('file', <FileStorage: u'Second_XML.xml' ('application/xml')>)])
Upload Files:
[]
Question:
Why request.files.getlist("file[]") is returning an empty list?
How can I post multiple files using flask test client, so that it can be retrieved using request.files.getlist("file[]") at flask server side ?
Note:
I would like to have flask client I dont want curl or any other client based solutions.
I dont want to post single file in multiple requests
Thanks
Referred these links already:
Flask and Werkzeug: Testing a post request with custom headers
Python - What type is flask.request.files.stream supposed to be?
You send the files as the parameter named file, so you can't look them up with the name file[]. If you want to get all the files named file as a list, you should use this:
upload_files = request.files.getlist("file")
On the other hand, if you really want to read them from file[], then you need to send them like that:
scc.data['file[]'] = # ...
(The file[] syntax is from PHP and it's used only on the client side. When you send the parameters named like that to the server, you still access them using $_FILES['file'].)
Lukas already addressed this,just providing these info as it may help someone
Werkzeug client is doing some clever stuff by storing requests data in MultiDict
#native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
class MultiDict(TypeConversionDict):
"""A :class:`MultiDict` is a dictionary subclass customized to deal with
multiple values for the same key which is for example used by the parsing
functions in the wrappers. This is necessary because some HTML form
elements pass multiple values for the same key.
:class:`MultiDict` implements all standard dictionary methods.
Internally, it saves all values for a key as a list, but the standard dict
access methods will only return the first value for a key. If you want to
gain access to the other values, too, you have to use the `list` methods as
explained below.
getList call looks for a given key in the "requests" dictionary. If the key doesn't exist, it returns empty list.
def getlist(self, key, type=None):
"""Return the list of items for a given key. If that key is not in the
`MultiDict`, the return value will be an empty list. Just as `get`
`getlist` accepts a `type` parameter. All items will be converted
with the callable defined there.
:param key: The key to be looked up.
:param type: A callable that is used to cast the value in the
:class:`MultiDict`. If a :exc:`ValueError` is raised
by this callable the value will be removed from the list.
:return: a :class:`list` of all the values for the key.
"""
try:
rv = dict.__getitem__(self, key)
except KeyError:
return []
if type is None:
return list(rv)
result = []
for item in rv:
try:
result.append(type(item))
except ValueError:
pass
return result
I am editing the Runwithfriends FB sample app to build one of my own. It was working fine and I was making a few changes here and there. I took a break from it for about a fortnight but now when I try to access the app, I get a strange python error:
C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT\app\main.py in init_facebook(self=<main.RecentRunsHandler object>)
316 user_id=facebook.user_id, friends=friends,
317 access_token=facebook.access_token, name=me[u'name'],
=> 318 email=me.get(u'email'), picture=me[u'picture'])
319 user.put()
320 except KeyError, ex:
<..some portion clipped..>
class 'google.appengine.api.datastore_errors.BadValueError'>: Property picture must be a str or unicode instance, not a dict
args = ('Property picture must be a str or unicode instance, not a dict',)
message = 'Property picture must be a str or unicode instance, not a dict'"
I know this is a very generic error but its pointing to the following code. This code has always been there and I have never touched it. I really do not know where else to look now - I have searched exhaustively but couldnt find a clue. Sorry, if this is still too broad but I would be glad if you can tell me what other info can I provide to debug this :-(
def init_facebook(self):
"""Sets up the request specific Facebook and User instance"""
facebook = Facebook()
user = None
# initial facebook request comes in as a POST with a signed_request
if u'signed_request' in self.request.POST:
facebook.load_signed_request(self.request.get('signed_request'))
# we reset the method to GET because a request from facebook with a
# signed_request uses POST for security reasons, despite it
# actually being a GET. in webapp causes loss of request.POST data.
self.request.method = u'GET'
self.set_cookie(
'u', facebook.user_cookie, datetime.timedelta(minutes=1440))
elif 'u' in self.request.cookies:
facebook.load_signed_request(self.request.cookies.get('u'))
# try to load or create a user object
if facebook.user_id:
user = User.get_by_key_name(facebook.user_id)
if user:
# update stored access_token
if facebook.access_token and \
facebook.access_token != user.access_token:
user.access_token = facebook.access_token
user.put()
# refresh data if we failed in doing so after a realtime ping
if user.dirty:
user.refresh_data()
# restore stored access_token if necessary
if not facebook.access_token:
facebook.access_token = user.access_token
if not user and facebook.access_token:
me = facebook.api(u'/me', {u'fields': _USER_FIELDS})
try:
friends = [user[u'id'] for user in me[u'friends'][u'data']]
user = User(key_name=facebook.user_id,
user_id=facebook.user_id, friends=friends,
access_token=facebook.access_token, name=me[u'name'],
email=me.get(u'email'), picture=me[u'picture'])
user.put()
except KeyError, ex:
pass # ignore if can't get the minimum fields
self.facebook = facebook
self.user = user
Might have to do with the October 2012 Breaking Changes, quote:
/picture connection will return a dictionary when a callback is specified
We will start returning a dictionary containing the fields url, height, width, and is_silhouette when accessing the /picture connection for an object and specifying a callback property. Currently we just return the picture URL as a string.
So at this point in your code, where you are currently using picture=me[u'picture'], try accessing the url property of the picture dictionary instead. (If it has one; I can’t tell you for sure if this is applicable, since I don’t know if your code would be considered as having specified a callback property.)
If my assumption is correct, you could also enable the migration as described in the roadmap; but that will only make your app work in the old way until Oct. 3rd, so probably better to try and fix it right away.
This is the way to get the picture:
picture=me[u'picture'][u'data'][u'url']