Bypassing Firestore Security Rules in jest tests - reactjs

Currently working on a React/Typescript/Firebase Firestore project. When writing Jest-tests for some actions/functions that are called from the UI, I ran into the following problem:
In the test file I'm able to setup the firestore client using the v9 api and make it talk to emulator
const app = initializeApp(config.firebase);
const firestore = getFirestore(app);
connectFirestoreEmulator(firestore, "localhost", 8080);
In addition I also found out how to setup the admin client and make it talk to emulator
process.env.FIRESTORE_EMULATOR_HOST = "localhost:8080";
const serviceAccount = require("../../../my-key.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
...config.firebase
});
The test itself looks something like this:
describe("createCompanyAndRating action", () => {
test("call createCompanyAndRating and make sure it creates a proper rating entity", async () => {
// omitted: set testRatingFormState and other test data that are passed as args and
// pass in the firestore db client
const {
ratingId,
companyId,
} = await createCompanyAndRating({
ratingFormState: testRatingFormState,
visitorId: testVisitorId,
firestore,
});
// verify result by fetching the rating entity from the emulator db using the admin client
const ratingPath = `companies/${companyId}/ratings/${ratingId}`;
const ratingSnap = await admin.firestore().doc(ratingPath).withConverter(ratingConverter).get();
const rating: Rating | undefined = ratingSnap.data();
// omitted: verify result with some Jest expect-statetments...
});
})
My problem is now that the Firestore security rules apply and only authenticated users can write docs in the collections used in the createCompanyAndRating function, so the test already throws an error when calling that function.
In this scenario I'm not interested in testing the security rules per se.
Is there a way to bypass the security rules for the test?
If yes, how do I have to setup the firestore client?
Is there even the possibility to somehow impersonate a user in the test?
In addition, please note that I can't to pass the admin client into the createCompanyAndRating function as the admin client API is different from the v9 firebase API that I'm relying on in the createCompanyAndRating function implementation (tried and it didn't work and not only because some type errors in the way).
Maybe my whole approach is a little misguided and I should rather concentrate on testing the internals of the createCompanyAndRating function where I do a lot of factory stuff that could be tested without db interaction.
Anyway, any help/guidance is much appreciated.

Thanks for confirming that I was looking in the right place (i.e. #firebase/rules-unit-testing). Finally figured out what the problem was, missed an "await" in createCompanyAndRating, so the firestore admin instance wasn't getting the data (and I though it was a admin config issue...) Thanks!

Related

Access SSM Parameter store value in an aws amplify react js application

I have an amplify application built using React JS, I have a scenario for which I am manually storing API keys in my SSM parameter store in my AWS account. However, I want to retrieve/get those values(JSON object) based on a key from my React JS app (client side). So, I have installed the aws-sdk, the AWS JavaScript sdk, and using the below code snipped I am trying to access the ssms parameter store
const AWS = require('aws-sdk');
AWS.config.update({region:'us-east-1'});
const ssm = new AWS.SSM();
const getSecret = async (secretName) => {
console.log(`Getting secret for ${secretName}`);
const params = {
Name: secretName,
WithDecryption: true
};
const result = await ssm.getParameter(params).promise();
return result.Parameter.Value;
};
module.exports = {getSecret};
I am receiving this error on running my application and while accessing the store using the getSecret function.
Unhandled Rejection (CredentialsError): Missing credentials in config,
if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
I believe that amplify configures the environment implicitly but since, the SSM Secrets manager is not supported yet by Amplify hence, I have to use the JS AWS SDK for this purpose. Can anyone help me spot the issue while configuring the service using AWS SDK? Or is there another or a better way to access parameter store from the client side?
Also, after surfing I have found a package named dotenv
Is it okay to store aws credentials in such a way?
Your code to fetch parameter store keys/values shouldn't be at client side considering security implications. It should be done at server-side and functionality can be exposed over endpoint for client-side.
You can read the credentials programmatically something like below:
var AWS = require("aws-sdk");
var credentials = new AWS.SharedIniFileCredentials({profile: 'profile name'});
AWS.config.credentials = credentials;
Refrence:
loading-node-credentials-shared
global-config-object

#firebase/firestore: Firestore (8.6.2): Could not reach Cloud Firestore backend (React Js)

I'm trying to connect my react js application with Firebase Firestore but I'm getting the below error as shown in the image error image I'm having 2 documents in the collection but I'm getting an empty array as you can see in the console. This is the code I'm using to fetch firestore data
const snapshot = await firebase.firestore().collection('users').get();
const data = snapshot.docs.map((doc) => doc.data());
console.log(data);
PS: I'm able to use auth function from firebase properly but getting an error with firestore.
Solutions I have tried so far:
Sync the clock
verified the firebase rules and made sure read and write are allowed (attaching the rules I found in firestore rules section)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if
request.time < timestamp.date(2021, 6, 23);
}
}
}
Looking for some quick solutions as I'm struggling since last night. Thanks in Advance.
I tried the following steps to confirm that there is a problem with the react application or browser and fixed the issue.
Tried to get data and post data to firestore using node and express
script (this helped to find out that the issue was not with firebase
configuration)
After some online research I tried to change my browser from Brave to
Chrome which actually worked.
The First error in your screenshot hints at this actually being a Access-Control-Allow-Origin CORS issue. So in order to fix it as you can see in this article, you can either:
Add the "proxy": "http://localhost:PORT_YOU_ARE_USING" option to your package.json file;
or
Use a middleware like http-proxy-middleware to proxy requests, you can follow the example in the article for that.
Also you can take a look at this community question, which poses a simillar issue to yours and provide some other solutions. You may get a better understanding of cors issues in React by checking it out.

"mock app" how to search through a database for matches? (react-native app)

Im working on a mock app as a project to have for my portfolio as a frontend developer.
So far i've been able to fairly accurately mock some posts requests in my app ( requests for fetching data, logging in, etc ) here is an example of my login func
export const loginUser = async ({
username,
password,
onSuccess = () => {},
onFailure = () => {},
}) =>
postReq({
endpoint: LOGIN_USER,
body: {
username,
password,
},
onSuccess,
onFailure,
});
all of my "Data" lives in a json file in my project file.
however not very familiar with the backend side of things, How would the backend normally perform a search that returns data ? and whats the closest thing i can do from the frontend? I've only recently discovered regular expression functions, is this a path in the right direction? Thank you very much, Im excited to keep learning.
I think you are using redux or useReducer kind of logic to handle your login. This seems fairly true what you did for authenticate user from frontend side.
For backend side;
1- You send your request(via axios, fetch, ajax etc) to your server(backend) like this and waiting for a response.
2- You are taking this information from your request body as you send this informations in your request body which is the preferred way.
3- You check for username in your database if there is a collasion, you will check for password correctness which i advice you to store your passwords hashed and check correctness via hash compare.
4-If there is no collasion or password is not correct you send an error with relative status code like 500 and a message "A user with
the given username and password could not be found"
5- If password is true, you send your feedback your frontend with a success status response(like 200).
6- You taking your response from your server and take the necessary actions accordingly
And keep up your passion you will have a lot of fun

How do you create a API/IdentityServer/Blazor(server-side) application?

I attempted to build this application myself but, have hit several stumbling blocks along the way. I am thinking that it may be best to step back and take a larger look at what I am trying to create. There doesn't seem to be any documentation on how to make what I am looking for. (unless someone can point me in the right place I might have missed)
Ultimately what I would like is to have a Blazor(server-side) application make API calls to use data in the app and then have an IdentityServer4 encapsulate the authentication. I need to have Azure as well as ASP.net Identity as the possible authentication methods.
I have tried and was able to create an IdentityServer4 that also has a local API. I can make calls to this from Postman to get token and such. But, when it comes to tying a Blazor(server-side) application to the IdentityServer4 I am befuddled.
I have tried to ask this question in specifics but, haven't gotten any results at all. I am hoping maybe this larger look at it might be helpful.
It seems like odic-client.js is the way to get the data from the IdentityServer4 callback but, that doesn't seem to tie in nicely with the .NET Authorization in Blazor(server-side). How do I get these to work together.
IMPORTANT: There are better sources now than my answer. Follow the links provided in the last part of this answer.
I've got a similar setup with API / IdentityServer4 / Blazor(server-side). I'll show you some of the code I used, maybe you can make some use of it.
Using the NuGet Package Microsoft.AspNetCore.Authentication.OpenIdConnect, I've got this code in the ConfigureServices method in the Startup class:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "myClient";
options.ClientSecret = "mySecret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("MyApi");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
});
and in the Configure method app.UseAuthentication();
Then in App.razor i used the CascadingAuthenticationState component:
<CascadingAuthenticationState>
<Router AppAssembly="typeof(Startup).Assembly" />
</CascadingAuthenticationState>
And using the NuGet package Microsoft.AspNetCore.Authorization in my main page Index.razor:
#using Microsoft.AspNetCore.Authorization
#attribute [Authorize]
Now it should say "Not authenticated" when you open the main page but there's still no redirection to the IdentityServer4. For this you've got to add MVC in the startup too, as I learned from this stackoverflow question:
services.AddMvcCore(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
Now you should be getting redirected to IdentityServer4 to log in after starting the application. In my case I've got an ApiClient, which describes the methods of my API. I use DI to inject the ApiClient and add the access token:
services.AddHttpClient<IApiClient, ApiClient>(async (serviceProvider, client) =>
{
var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("http://localhost:55578");
});
Like you said, there is not much documentation on this topic except some answers here on stackoverflow. It took me a long time to set this up, so I hope I can help someone else with this post.
UPDATE: Logout process
Logging out with this setup requires a detour to a razor page because the HttpContext is inaccessible after the blazor component is loaded.
Create a new Razor Page in the Pages folder and add the following code to the newly created Logout.cshtml.cs:
public class LogoutModel : PageModel
{
public async void OnGetAsync()
{
await HttpContext.SignOutAsync("Cookies");
var prop = new AuthenticationProperties()
{
RedirectUri = "http://localhost:62909"
};
await HttpContext.SignOutAsync("oidc", prop);
}
}
Add a logout button somewhere which calls the function UriHelper.NavigateTo("/Logout") relying on #inject IUriHelper UriHelper. Done!
UPDATE: Login Workaround
The previously described login process worked locally but after publishing to the test server, I had the problem, that the IHttpContextAccessor was always null inside the AddHttpClient method. So I ended up using the same workaround as with the logout process. I let the IdentityServer redirect to a razor page (which always has a HttpContext), save the access token in the user claim and redirect to the index page. In the AddHttpClient method I only get the token from the user claim and put it into the authentication header.
UPDATE: Open issues
I still struggle to get this setup working on our server. I opened this issue and requirement on the AspNetCore Github but both got closed without a proper answer. For the time being, I found some blogs that give a good overview of the current state of the topic:
https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html
https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/
Try this
Blazor Consume IdentityServer4 Protected API

How to use the SalesForce API?

I'm trying to use an express/node application to make an api call to the salesforce api and return me data according to the records I have with the account.
But it is returning this:
[{"errorCode":"NOT_FOUND","message":"The requested resource does not exist"}]
Currently my code looks like this
const express = require('express')
const app = express();
var request = require('request');
app.get('/',(req,res, next) =>{
request({
url: 'https://nav4.lightning.force.com/services/data"',
}).pipe(res);
});
})
const port = process.env.PORT || 3000; app.listen(3000, ()=>
console.log(`listening on port ${port}`))
I think my URL is wrong and might need authentication also.
You do need to authenticate first to https://login.salesforce.com. I would suggest reading and following the documentation at their documentation. The username password flow is only recommended for testing purposes though, so once you get it working you might want to look into a different oauth flow if you are building a real application depending on your use case.
For consume the Salesforce API below are the Details to notes.
Find which api to consume REST OR SOAP
Needs :
Base URL
Endpoint URL
Consumer Key and secret key
This are the Point To archive
Below are for Your Reference
https://developer.salesforce.com/page/Consuming_Force.com_SOAP_and_REST_Web_Services_from_.NET_Applications
https://trailhead.salesforce.com/content/learn/modules/apex_integration_services

Resources