How to avoid running entire client-side process in Blazor WebAssembly before Azure AD authentication? - azure

I'm building a Blazor WASM app with Azure AD, and I'm struggling with what appears to be an inefficiency in the way it's designed. The entire application, including the home page, needs to be secured by [Authorize]. It works (with one exception noted below), but the initial load is painfully slow. Basically, on reaching the home page, Blazor loads the entire application -- running Program.Main in it's entirety, loading JS files from CDN or webpack bundles, loading all the .NET dlls, and THEN decides that it needs to redirect to Azure to authenticate. Once it returns, it does all that again. Loading the various files is not too much of a problem, since it gets them from the browser cache the second time. The problem is that is also needs to run Program.Main again.
In my rather large client app, it takes a few seconds to configure all the services (I'm using a lot of gRPC). The biggest culprit though is a call to the server API to get certain app settings that I don't want to expose to the client (basically doing this). Moreover, that API call doesn't even succeed, since the API endpoint is secured, and the user hasn't authenticated yet, but I don't know how to get the user info from within Program.Main. The log messages show that the user identity is not even created until sometime after Program.Main completes. (One of the settings is the roles-to-permissions mapping, so I can't even draw the app's menu without it. I've resorted to removing the auth requirement from the API controller for now, obviously not a permanent fix)
To replicate the behavior, just create a brand new Blazor WebAssembly app, selecting Auth Type = Microsoft identity platform, and checking the ASP.NET Core hosted box. Then just edit both appsettings.json files to provide your Azure login info; change the requested scope in Client.Program.Main (and change the one in WeatherForecastController to match); and add [Authorize] to the _imports.razor file, and [AllowAnonymous] to Authentication.razor. Finally add some logging Console.WriteLine("Running in Client.Program.Main"); near the end of that method.
In the basic Blazor app template as described above, this all runs pretty fast. Once there's a significant amount of startup code in Program.Main, though, it becomes quite noticeable, it can be several seconds both before and after the login redirect. And I can't make an authenticated API call.
Specifying endpoints.MapFallbackToFile("index.html").RequireAuthorization(); in the server side Startup doesn't seem to make any difference. Neither does adding options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); to the AddAuthorization call.
So basically, I'm looking to:
Identify the user in Client.Program.Main, so I can make a secure call to the settings API
Identify the user in Client.Program.Main, so I can bypass all the time-consuming stuff myself on the first pass
Get Blazor (server?) to somehow recognize that a request for a protected page will fail for an unauthenticated user, and go directly to the Azure login page without all the usual ceremony
Any suggestions?

Related

How to embed a web browser inside a web app made in node.js ?

I currently have a web app made in node.js. One feature of this app is to take notes. I want to provide the user with a way to browse the internet and select a text to add as a note in our web app without having to manually copy-pasting from one browser window to our app.
I know I can do this relatively simply using a Chrome extension that would be linked to the user account and would save the note to the database. However, I cannot use this approach since not all my users can install Google Chrome.
Therefore, I am looking for a way to browse the web from inside our web app. For example, it could be in an iFrame where we display a complete browser. That way, the user could navigate the web for information from inside the app, select text to save and click on a button (probably located outside the iFrame browser) to save the selected text as a note in our database.
How can I achieve such a thing in node.js ?
This is, essentially, impossible.
For you to get any data about the site the user was browsing you could either:
Restrict them to browsing sites willing to partner with you to give you permission to access their data via postMessage (a technical change on their part to work around the Same Origin Policy)
Proxy every request through your server which would:
Have large bandwidth requirements
Require a lot of rewriting of URLs (including dynamically generated ones in JS)
Require rewriting of X-Frames-Options and Access-Control-Allow-Origin headers
Need users who would trust you with all the data you passed through your system (including their passwords to third party sites)
Not work for Intranet sites (since your server could not reach them)

Unable to log in to Azure web app via VS2015 web performance test

How do I correctly handle the login/authentication scenario for an Azure web app in my VS2015 web performance test?
I created an XML file as a data source for the WAAD username and password. I bind the username and password to the Form Post Parameters: login and passwd respectively at request: https://login.microsoftonline.com/xxxx/login
But when I run the test, the Web Browser tab shows this error:
We can't sign you in
Your browser is currently set to block JavaScript. You need to allow
JavaScript to use this service.
To learn how to allow JavaScript or to find out whether your browser
supports JavaScript, check the online help in your web browser.
I also get a number of errors like this:
The value of the ExpectedResponseUrl property
Validation xxxx.azurewebsites.net/xxxx/docs/xxxx.aspx does
not equal the actual response URL
login.microsoftonline.com/xxxx/wsfed. QueryString
parameters were ignored.
Any idea how I can successfully log in to the Azure web app via the web performance test?
There are several methods of login and authentication that can be used. Just binding values to form post parameters may not be sufficient or correct. You will find the login form has hidden session identities that must be passed as well as the login data. I find that recording a test two times using as nearly as possible the same inputs and doing the same activities helps. These two tests can then be compared to find the dynamic data that needs to be handled.
In a comment the questioner added "I noticed these parameters, n1-43 are different but I have no idea what they represent. How do I handle them?". I can have no idea what they represent as I do not know the website you are testing. You could ask the website developers. Or, better, treat them as dynamic data. Find where the values come from, save them into context variables and use them as needed. This is basic web test development. Here and here are two good articles on what to do.
The message about JavaScript not being supported can be ignored. Visual Studio web tests do not support JavaScript or any other "active" parts of a web page, they only support the html part. Your job as a tester is to simulate what the JavaScript does for the specific user journeys you are testing. That simulation is generally just filling in the correct values (via context parameters) in the recorded requests.
Unexpected response urls can be due to earlier failures, such as teh login not working. I suggest not worrying about them until all of the other test problems are solved. Then, if you need help ask another new question.

Disable direct requests to REST API

I'm making a REST backend for private use of our frontend, they will both be in the same server.
The problem is that I'm worried about security issues, I don't want a attacker to use the API directly, either by JS or by using other REST client.
Lets take this service as an example
http://myserver:8080/something/webresources/film
That's a service that allows to GET, PUT, POST, DELETE I want that only the frontend be able to use it, otherwise since anyone can see client-code it would be easy to get the endpoint and start putting or getting data. I do have BASIC AUTH so they would have to register and if they did something wrong I would be able to see who did it, but that doesn't solve the problem.
I could implement access control so that a user only could get/update/delete their own movies, but I would have to do that for every REST service(I have over 100 by now), plus I might need to actually get others movies
This is my first public project, I am really lost.
You can do it through your web server. I'm using Nginx. I have an if statement that checks the $http_referer. If it returns nothing, or the value returned is not my application/frontend page (meaning someone is trying to hit the api directly), it'll return a 403 forbidden page.
If your application doesn't send out emails to your users don't worry about the following: I added a block to allow access to my static images as the only exception, as my application sends out emails with images and I don't want them to break.
That's it. Problem solved. No one has access to my api except my frontend page/application, unless they can forge the $http_referer to match my domain which if they can do that then they deserve to break in.
Your only option to call the REST API from server side. You cannot hide from the users what's going on in their browser... You can have a layered application, so the frontend layer can call the backend layer on the server while the client can see only the frontend. (Check the layered system constraint.)

Could not retrieve the CDN endpoints in subscription with ID

Searched Google and so - no luck.
Just got this message in Azure for 3 CDN endpoints.
There seems no way to know what is going on without MS support. It is a test account and I do not recall setting this. I have been through similar obfuscated MS error messages only to discover that Azure had crashed.
What does it mean?
This isn't really a direct answer, but could help with the general problem of "what happens if the CDN goes down?".
There is a recent development called the "Progressive Web App".
Basically unless served by localhost, everything has to be over https, but script is cached as a local application in your browser.
When your app makes requests to the registered domain, these are intercepted by a callback you put in your serviceWorker.js, so you can cache even application data locally, and sync the local data occasionally with the server (or on receive events if you're using webSockets).
Since the Service Worker intercepts REST calls to the registered domain, this in theory makes it fairly easy to add to just about any framework.
https://developers.google.com/web/fundamentals/getting-started/codelabs/your-first-pwapp/
Sometimes there is a (global) problem with the CDN. It happend before.
You can check the azure CDN status on this page: https://azure.microsoft.com/en-us/status/
At this moment everything looks good, you still have problems?

Can a ClickOnce application return a value to the page that loaded it?

I have an online ClickOnce application that launches from a web page. After the application is closed, I would like the user to return to that page with some results passed from the application. Is this possible?
Right now the only solution I have is for the application to upload the results to my server, and have javascript on the launching webpage to poll the server every 15 seconds as it waits for results.
No. It is not possible to pass information directly back to the client browser from the ClickOnce installed application.
Your intuition is correct that you should have your application upload results to the server (presumably with the help of WCF) for subsequent processing and display via your polling page.
I'll also add, that in terms of your web application linking to data from the ClickOnce application you will need to come up with a common token between the web application and the ClickOnce application. Perhaps via a customised activation URL link that uses a common GUID generated for the client (e.g. http://myserver.com/myapplication.application?id=18c40c3d-183c-4c22-8127-37cac3be6492).

Resources