Firebase Security Rules? - json

I seem to be having a hard time with firebase security rules. I've read the guides, but the simulator results aren't descriptive enough (Would be much easier if we could just hover over a node, and a button pops up where we can update the rules).
Here's what my structure looks like:
chats
- randomChatId01
- name: "awesome chat"
- members:
- userId01 : true
- userId02 : true
- randomChatId02
- members:
- userId02 : true
- randomChatId03
- members:
- userId01 : true
- userId02 : true
- ...
I only want a user to be able to read the chat nodes in which the node's child node members contains the authenticated user's auth.uid.
So in this case if userId01 were logged in, she would only have read access to randomChatId01 and randomChatId03.
This is the rule I have:
{
"rules": {
"chats": {
"$chat": {
".read": "data.child('members').val().contains(auth.uid)"
}
}
}
}
However it's returning the following in the simulator:
Attempt to read /chats with auth={"provider":"anonymous","uid":"eF4ztDEXz7"}
/
/chats
No .read rule allowed the operation.
Read was denied.

This is because Firebase Security Rules are evaluated at the location that you read from.
You're trying to read /chats. The user does not have read permission to /chats, so the operations fails straight away.
If you read /chats/randomChatId01 as userId01 it will succeed.
This is covered in the documentation section rules are not filters. Also see Michael Lehenbauer's answer here: Restricting child/field access with security rules

Related

How to work with configuration files in Airflow

In Airflow, we've created several DAGS. Some of which share common properties, for example the directory to read files from. Currently, these properties are listed as a property in each separate DAG, which will obviously become problematic in the future. Say if the directory name was to change, we'd have to go into each DAG and update this piece of code (possibly even missing one).
I was looking into creating some sort of a configuration file, which can be parsed into Airflow and used by the various DAGS when a certain property is required, but I cannot seem to find any sort of documentation or guide on how to do this. Most I could find was the documentation on setting up Connection ID's, but that does not meet my use case.
The question to my post, is it possible to do the above scenario and how?
Thanks in advance.
There are a few ways you can accomplish this based on your setup:
You can use a DagFactory type approach where you have a function generate DAGs. You can find an example of what that looks like here
You can store a JSON config as an Airflow Variable, and parse through that to generate a DAG. You can store something like this in a Admin -> Variables:
[
{
"table": "users",
"schema": "app_one",
"s3_bucket": "etl_bucket",
"s3_key": "app_one_users",
"redshift_conn_id": "postgres_default"
},
{
"table": "users",
"schema": "app_two",
"s3_bucket": "etl_bucket",
"s3_key": "app_two_users",
"redshift_conn_id": "postgres_default"
}
]
Your DAG could get generated as:
sync_config = json.loads(Variable.get("sync_config"))
with dag:
start = DummyOperator(task_id='begin_dag')
for table in sync_config:
d1 = RedshiftToS3Transfer(
task_id='{0}'.format(table['s3_key']),
table=table['table'],
schema=table['schema'],
s3_bucket=table['s3_bucket'],
s3_key=table['s3_key'],
redshift_conn_id=table['redshift_conn_id']
)
start >> d1
Similarly, you can just store that config as a local file and open it as you would any other file. Keep in mind the best answer to this will depend on your infrastructure and use case.

CloudFormation Template - any way to get a Spot-Fleet-Request ID?

I'm attempting to create a single template that creates the following:
AWS::EC2::SpotFleet resource
2 AWS::ApplicationAutoScaling::ScalingPolicy resources (scale up, scale down)
Initially, my template included only the SpotFleet resource, and I confirmed that the stack would create without issue. Once I added the ScalingPolicy resources, the stack would rollback because there was "No scalable target registered for namespace..." So, I added an additional resource.
AWS::ApplicationAutoScaling::ScalableTarget resource.
(From http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationautoscaling-scalabletarget.html#cfn-applicationautoscaling-scalabletarget-resourceid)
{
"Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
"Properties" : {
"MaxCapacity" : Integer,
"MinCapacity" : Integer,
"ResourceId" : String,
"RoleARN" : String,
"ScalableDimension" : String,
"ServiceNamespace" : String
}
}
The ResourceID is a required property. I have the data for all the other properties, but when researching what data is needed for the ResourceID property, I have found that the data I need is the spot-fleet-request ID, (something like this: "SpotFleetRequestId": "sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE").
So here's the problem: Since I am creating the spot fleet request in the same template as the scaling policy, I can't put the SpotFleetRequestId in manually, since to my knowledge this is created when the resource is and there's no way to anticipate what the request ID will be. In other templates, with other kinds of resources, I've simply used "Ref" or "Fn::GetAtt" to pass in the arn of a resource without having to manually input this. However--there seems to be no way to do this with a SpotFleetRequestID. All the research I've done has turned up nothing, not even a single template example that uses a method like I'm describing - the only examples available assume that the scalable target resource already exists and the SpotFleetRequestID is known prior to creating the ScalingPolicy.
Does anyone have any idea if referring to the SpotFleetRequestID of an AWS::EC2::SpotFleet initialized in the same template is even possible? Or am I just missing something REALLY obvious?
-KungFuBilly
Turns out that if you "Ref" the logical name of the AWS::EC2::SpotFleet it will return the request ID. Then, it's a matter of using "Fn::Join" to get the right data for the ResourceID. Should look something like this:
"ResourceId": {
"Fn::Join": [
"/",
[
"spot-fleet-request",
{
"Ref": "SpotFleet"
}
]
]
},
That will output: spot-fleet-request/"SpotFleetRequestID"

Output my JSON data before I use Firebase $save or $add in console?

I've been trying to debug for hours a Firebase rule problem and was wondering if there is something easier available.
My problem is that I save my firebaseObject with $save (or create with $add) and get a permission denied because of my rules. However, both the rules and the object is pretty complex and there are dozens of rules which are involved. In my simulator, I think I got it all, but still get permission denied.
The problem is that I am not 100% sure how the JSON data actually looks which $save tries to send to Firebase. If I use the normal console.log(myObject), I get of course a list of all values and functions inside this object, but this isn't the same as the raw JSON I would expect (like { "name": "value" }).
Is there any way to display the actual plain JSON data $save sends to copy this into the rule simulator and debug? Or is there any other way to see which exact permission is denied?
Otherwise, I have to go one by one, switching my permissions off and on which would be a pretty long night for me. :(
If the value of the $firebaseObject is an object, the only difference (in addition to the prototype-wired methods) should be a number of $-prefixed properties (like $id and $resolved). So you should be able to see the actual JSON of what will be written to the database using something like this:
var written = {};
Object.keys(myObject).forEach(function (key) {
if (key.charAt(0) !== "$") { written[key] = myObject[key]; }
});
console.log(JSON.stringify(written));
The $$hashKey entries mentioned in your comment are added by AngularJS. A more general mechanism could be used to remove/ignore all $-prefixed keys throughout the object:
console.log(JSON.stringify(myObject, function (key, val) {
return key.charAt(0) === "$" ? undefined : val;
}));

How do I ensure Firebase database structure using anonymous auth?

I have a public-input type app using Firebase, with anonymous auth. The user data is used to create points on a map. Each anonymous user can only edit the data inside the node matching their auth id - via security rules.
However, my app depends on a certain database structure. How do I ensure my database structure/integrity using anonymous auth, since the database url is client-side readable?
I think it is possible with security and validation rules, but I'm not sure. Maybe deny children creation in a node? This would be necessary to ensure the schema is followed.
Each auth node can have many key nodes, but I would want to limit this Firebase-side. And each key node must follow the schema below (so I can pull out the geojson easily). Below is my current setup - wondering what is missing?
"features" : {
"5AGxfaK2q8hjJsmsO3PUxUs09Sz1" : {
"-KS3R4sWPdcDkrxyIFX6" : {
"geometry" : {
"coordinates" : [ -81.88247680664062, 38.884619201291905 ],
"type" : "Point"
},
"properties" : {
"color" : "#2be",
"title" : ""
},
"type" : "Feature"
},
Authentication and database schema are completely separate topics. You ensure database schema by using a combination of .write and .validate rules in your security doc, not by anything to do with your authentication provider (i.e. Anonymous authentication).
This is described in detail in our database security guide.
A quick summary:
hasChildren: specify required fields
newData: refer to the data being written
data: refer to data already in the database
.validate: specify data schema using things like newData.isString() or newData.val() == data.val() + 1
Keep in mind that .validate rules are only run for non-null values. Thus, if you want to try something like !data.exists() (i.e. you can only write to this path once and can't modify it later) or newData.exists() (i.e. you can't delete this data) then you need to specify those in a .write rule.
Refer to the guide for more detail.

REST service semantics; include properties not being updated?

Suppose I have a resource called Person. I can update Person entities by doing a POST to /data/Person/{ID}. Suppose for simplicity that a person has three properties, first name, last name, and age.
GET /data/Person/1 yields something like:
{ id: 1, firstName: "John", lastName: "Smith", age: 30 }.
My question is about updates to this person and the semantics of the services that do this. Suppose I wanted to update John, he's now 31. In terms of design approach, I've seen APIs work two ways:
Option 1:
POST /data/Person/1 with { id: 1, age: 31 } does the right thing. Implicitly, any property that isn't mentioned isn't updated.
Option 2:
POST /data/Person/1 with the full object that would have been received by GET -- all properties must be specified, even if many don't change, because the API (in the presence of a missing property) would assume that its proper value is null.
Which option is correct from a recommended design perspective? Option 1 is attractive because it's short and simple, but has the downside of being ambiguous in some cases. Option 2 has you sending a lot of data back and forth even if it's not changing, and doesn't tell the server what's really important about this payload (only the age changed).
Option 1 - updating a subset of the resource - is now formalised in HTTP as the PATCH method. Option 2 - updating the whole resource - is the PUT method.
In real-world scenarios, it's common to want to upload only a subset of the resource. This is better for performance of the request and modularity/diversity of clients.
For that reason, PATCH is now more useful than PUT in a typical API (imo), though you can support both if you want to. There are a few corner cases where a platform may not support PATCH, but I believe they are rare now.
If you do support both, don't just make them interchangeable. The difference with PUT is, if it receives a subset, it should assume the whole thing was uploaded, so should then apply default properties to those that were omitted, or return an error if they are required. Whereas PATCH would just ignore those omitted properties.