Stripping ContextPath in WebFlux router? - kotlin

I have a WebFlux application that is behind nginx-ingress.
In order to have redirect working (for purposes of Spring Security OAuth) I enabled ForwardedHeaderTransformer.
Now redirects generated by Spring Security OAuth are working fine, but the problem arises when I want to access my API exposed by RouterFunctions.
For instance I have an endpoint GET /someresource. When request is made ForwardedHeaderTransformer adds /api/myservice both to contextPath and uri.
Question is how to expose my api without adding /api/myservice to router function?
Is there any (clean) option to strip contextPath (if it's present) and serve API like this:
fun router() = router {
"/someresource".nest {
GET("/", myHandler::getResource)
GET("/{id}", myHandler::getResources)
Maybe there is a WebFilter that can be triggered just before RouterFunctions or maybe it can be modified in the other way?
I've tried to add HandlerFilterFunction to my router. But it does not work since there is no mapping for /api/myservice registered.

Related

You must subclass the WebAuthenticatorCallbackActivity and create an IntentFilter for it which matches your callbackUrl

I am building a Xamarin Forms application with Google Authentication via OAuth2. There are quite a few examples of integrating Google Authentication into Xamarin forms but most of these posts appear outdated.
The most recent instruction from Microsoft is to use Xamarin Essentials based on this MSDN post. Microsoft's advice is to leverage a web backend to proxy the request to the third-party identity provider. In this case, I will be using an ASP.NET Core backend.
Within the Google cloud console, I have configured the redirect url of the OAuth web application to point to my deployed service instance in the cloud. This url is:
https://my-google-app.appspot.com/signin-google
Assuming my ASP.NET Core app is exposed at base url https://my-google-app.appspot.com.
In MobileAuthController, that provides the authentication URL for the application, copied from this Github repo, the callback scheme is supposed to be the URL registered in my app for deep linking as per my understanding of the flow so far:
someappname://abc
assuming the package name of my Android application is com.my-app-package-name. This all appears or sounds reasonable.
Somewhere in the mobile application, I am initiating the authentication request using the Xamarin Essentials package as follows:
var result = await WebAuthenticator.AuthenticateAsync(
new Uri("https://my-google-app.appspot.com/mobileauth/Google"),
new Uri("someappname://abc"));
In my Android project, I have an intent filter defined as follows:
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new []{Android.Content.Intent.ActionView},
Categories = new[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
DataPath ="abc",
DataSchemes = new[]
{
"someappname" /* package id */
})
]
public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
{
}
}
So far, so good :). However, when I run the application, I get the error:
System.InvalidOperationException: 'You must subclass the
WebAuthenticatorCallbackActivity and create an IntentFilter for it
which matches your callbackUrl.
I have not been able to make sense of that error as Google will to redirect to my deployed ASP.NET instance which would then redirect to my app from my understanding.
UPDATE:
Correct my callback URL and problem persists.
This specific issue was being caused by a trailing slash in my redirect URL causing a mismatch between what I thought I was sending vs what the Xamarin app was constructing.
I ended up defining my redirect url as
someappname://callback/
The trailing slash ensures I can guarantee the same Uri being constructed on the Android intent which I then defined as follows:
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new []{Android.Content.Intent.ActionView},
Categories = new[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
// need to ensure we have a backslash
DataPath = "/callback/",
DataScheme = "someappname")
]
public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
{
}
The c# Uri class will append a trailing slash at the end of your custom scheme if defined without a trailing slash and this would cause confusion as you do not expect this. The MSDN docs is not clear on this.

Sending xAPI statement to a web application instead of LRS

I have an xAPI content made by storyline I want for the statement to be sent to a webapp instead of the LRS.
this webapp is developped using laravel, and user should be authenticated with email and password to use it.
what I did to send the statement to this app:
1.in the webapp I created an API endpoint route that use POST method.
2.in the xAPI wrapper I changed the endpoint in the configuration to the route I made in the webapp.
const conf = {
"endpoint":"here I added my api endpoint route of the webapp",
"auth":"Basic " + toBase64(""),
}
now whith any interaction with the content where a statement should be sent the request making cors error like in the picture down, I think this is authentication error, how can I add my authentication credentials to the xAPI wrapper?
Your non-LRS LRS is probably not handling preflight requests which are necessary for CORS handling. Most common LRSs will handle those requests appropriately since they expect to be accessed from additional origins. See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests
Also note that you'll likely run into issues unless you also handle state requests.
Additionally unless you are requesting the credentials from the user during runtime then hard coding the credentials into the package isn't a great idea from a security perspective.

How to update options in Restsharp v107 (RestClientOptoins)

I'm not finding any RestClient method to update its options, what I need to do is for example disable FollowRedirects for certain requests.
How do I do the following but with v107?
client.FollowRedirects = false;
Background: maybe a separate issue but current problem is that RestSharp is not following a redirect URL to Okta from a Location header of a response, it goes to the main Client URL instead. That is why I've decided to disable redirects to try following the redirect manually.
Most if not all of the properties in RestClientOptions are used to configure the HttpMessageHandler instance wrapped by RestClient. As each RestClient instance wraps a single HttpClient (and its handler), those options cannot be changed. It works the same way as configuring HttpClient, where you cannot change the AllowAutoRedirects property of the handler once it's configured.
That's why the documentation suggests using a specifically configured RestClient instance per remote API. Normally, the API uses a single convention and configuration requirement.
I have seen that some authentication endpoints require redirects, but most of the time the RestClient instance used to get the authorization token is not the one used to access the API itself with the retrieved token. So, the solution would be to have a separate instance for that purpose. Normally, it's only used once to get the token, then you can dispose it and reuse the token.
I keep posting the authenticator example from the docs https://restsharp.dev/usage.html#authenticator
Concerning RestSharp not following redirects properly, it's not what RestSharp does as it doesn't compose or execute HTTP calls physically. It just wraps HttpClient.

ASP.NET Core Google Auth for multi-tenant apps with single callback url?

I am building a multi-tenant asp.net core app based where tenants are selected by host names. So tenant1.example.com, tenant2.example.com, ..., and so on.
Also, I'm using Google authentication using the default Google auth handler in asp.net core services.AddAuthentication(...).AddGoogle(...)
It's working great, except that Google doesn't support wildcard callback URLs. So every time I add a new tenant, I have to configure my Google app with a new callback URL to reflect the new host: tenant1.example.com/signin-google, tenant2.example.com, ..., and so on.
The asp.net core Google handler lets you specify the callback path, but not the URL. I plan to overwrite the handler to have the callback URL always go to a redirector url hosted on the naked domain, example.com/redirect-google (I'll be careful about open redirects), and have that redirect to the appropriate sub-domain to complete the authentication.
Has anyone done this before? Anyone see a problem with this approach?
You are right that the authentication system does not allow you to further modify the host for the OAuth redirect URI. This is mostly done to make the system host name agnostic, which is a common pattern that is used throughout the framework (basically every URL generation is based on the current context).
As a workaround, what you could do is set up your own authentication handler for the Google scheme. You can actually inherit from the GoogleHandler and override the BuildChallengeUrl. That method is called to actually build the challenge URI of the authentication provider. It gets passed the redirectUrl which is the callback route of the OAuthHandler (the thing you cannot change the host name of).
So by overriding the method, you can simply change the redirectUrl that gets passed and replace it with the general URL that you want to use.
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
return base.BuildChallengeUrl(properties, "https://example.com/redirect-google");
}
When you do that, you will just have to replace the GoogleHandler in the DI config:
services.AddTransient<GoogleHandler, ReplacedGoogleHandler>();

Passport basic authentication only for API requests

I'm writing an express/node/angular application. When the client-side angular controllers need some data, they request it from the server using an endpoint that returns JSON.
This endpoint is behind some passport.authenticate('local') middleware, however this endpoint is exactly what we need for a public API.
Our API uses a passport.authenticate('basic') (basic http auth).
I'm trying to find a way to use the same URL for both, but I don't want users to my site who aren't logged in to see an http authentication window. I somehow need to tell "is this an API request, or an xhr request from the site"
For example, I want the following URL to work for a locally-authenticated user (would have been authenticated via a /login route) or for an API user:
app.get('/api/v1/tasks', passport.authenticate('basic'), tasks.list);
The only alternative I know of that works is splitting these into two different URLs, one for the site to use internally, and one for the public API. Maybe that's a better strategy for security/organization anyway?