IdentityServer (OpenId Connect) authentication on asp.net webform - webforms

i'm trying to use IdentityServer3 to authenticate users on an asp.net webform application with owin pipeline (no mvc)
All the examples suggest to configure the application like a mvc application, but in this way the application doesn't perform a redirection to the IdentityServer Login page when i try to access to a protected resource of the webform application
this is my client (webform) configuration
[Startup.cs]
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
//LoginPath = new PathString ("/Account/Login") //<--enabling this path property redirect me to a local login page but not to the external IdentityServer login page
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44300/identity", //<<--url of the identityServer
ClientId = "webform",
ClientSecret = "ciccio",
Scope = "openid profile roles",
RedirectUri = "https://localhost:44302/", //<-- url of the client (to come back ofter the login)
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies"
});
i'm sure i forgot something

It looks, you missed app.UseStageMarker(PipelineStage.Authenticate); at the bottom of your Startup.cs.
The reason is that (according to the documentation):
Owin middleware components (OMCs) run at the latest stage, which by default is PreHandlerExecute. The stage markers are used to make them to run earlier.
The complete sample including cookie mapping and support for logout is in IdSrv repo
posting this just in case someone else's still looking a solution for the same problem like we did recently, finding this question without an answer

as workaround i tried these solution suggested in this article but they DON'T WORK
Login page on different domain
both solutions in the example page force a "brutal" redirection to the IdentityServer, but doing so, the IdentityServer doesn't show you the login page because the performed request is not in the correct form
the "signin=xxxxxx" parameter attached to the querystring, needed to legitimate the login request is not present.
i've tried to use an mvc client as well, in this case every requests made to a protected resource (with Authorize attribute) is redirected to the IdentityServer in the correct way (the url where the user should be redirected to log-in page is in this format https://localhost:44300/identity/login?signin=4f7ee6677aec2d2aca6ebc40e4d13720) with the "signin" parameter attached to the querystring
this behaviour doesn't happen in a webform application (at least with the same configuration used in a mvc application)
I'm sure that something is missing, something like a "httpModule" that intercepts the "http 401 not authorized response" and composes a correctr url to redirect towards the login page of the IdentityServer
forgive me for my english

Related

Google Identity for server-side web app - redirect URI mismatch

I'm attempting to set up the Code Model for Google authentication, so that my user can oauth with Google and my app can retrieve their Calendar data. I'm stuck on step 5 here, where I'm supposed to exchange the authorization code for refresh and access tokens. I'm using nestjs in the backend and React in the frontend.
What I've done already that's working:
User clicks a button on my web app's page
Client sets up google.accounts.oauth2.initCodeClient with the /calendar scope, in ux_mode: popup
User is shown the Google popup and can auth thru that
Client receives a response from Google containing the authorization code
Client makes a POST call to my backend to send it just that authorization code
In step 5, the client makes the POST call to localhost:4000/auth/google-test. In the backend, I'm using the googleapis package and have:
export const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
'http://localhost:4000/' // <- note, I'm not sure if this is corect
);
And in the relevant controller route, I'm doing:
#Post('google-test')
public async googleTest(#Body() bodyReceived: any): Promise<any> {
let { code } = bodyReceived
let { tokens } = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
console.log('Tokens: ' + tokens);
return
The error I'm getting is related to oauth2Client.getToken(code), and the error is a redirect_uri_mismatch. In GCP for the credentials for this app, I've added all of these as "Authorized redirect URIs":
http://localhost:3000/home
http://localhost:4000/auth/google-test
http://localhost:4000
What am I doing wrong?
It took a bit more Googling, but turns out that the right answer is to have my server make the token call with the redirect uri as "postmessage".
This SO question gives a bit more context. A somewhat unbelievable message, but it seems to work for my app.
It is evidently that what is happening is that the redirect URI does not match with the one in the GCP. This usually happens because backend tools such as Nestjs may be appending a trailing '/' to the URL and it may be interpreted as being part of the redirect_uri value.
You can try by temoving any trailing '/' via this following method oauthurl.replace(/\/$/, '')
Moreover, you can pass the generated auth URL to a meta tag. And check the html header to confirm what is the URL value.

Microsoft Teams App - Add Authentication and Authorization for Task/Fetch Card Action

Located in the BotBuilder-Samples GitHub repo: https://github.com/microsoft/BotBuilder-Samples
There is a sample app: 54.teams-task-module. This app demonstrates a task/fetch action with a Url to a Custom Form which is rendered by a Razor Page.
https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/csharp_dotnetcore/54.teams-task-module
In the Bot, the OnTeamsTaskModuleFetchAsync method is overridden to return a TaskModuleResponse which tells the system to fetch the URL passed back to Teams in the response.
https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/csharp_dotnetcore/54.teams-task-module/Bots/TeamsTaskModuleBot.cs
protected override Task<TaskModuleResponse> OnTeamsTaskModuleFetchAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
{
var asJobject = JObject.FromObject(taskModuleRequest.Data);
var value = asJobject.ToObject<CardTaskFetchValue<string>>()?.Data;
var taskInfo = new TaskModuleTaskInfo();
switch (value)
{
case TaskModuleIds.YouTube:
taskInfo.Url = taskInfo.FallbackUrl = _baseUrl + "/" + TaskModuleIds.YouTube;
SetTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);
break;
case TaskModuleIds.CustomForm:
taskInfo.Url = taskInfo.FallbackUrl = _baseUrl + "/" + TaskModuleIds.CustomForm;
SetTaskInfo(taskInfo, TaskModuleUIConstants.CustomForm);
break;
case TaskModuleIds.AdaptiveCard:
taskInfo.Card = CreateAdaptiveCardAttachment();
SetTaskInfo(taskInfo, TaskModuleUIConstants.AdaptiveCard);
break;
default:
break;
}
return Task.FromResult(taskInfo.ToTaskModuleResponse());
}
I have enabled developer tools in Teams and watched the network requests, as well as overridden every method I can find to try find an extensibility point to inject some sort of token into the request so that the URL can be secured from public anonymous access.
Question: The only way to provide authorization on the Razor Page I see right now is passing the token on the query string and using a custom authorization handler to process the token.
Is there a better way to inject a token or any other info into the task/fetch request so that the request can be authenticated and authorized?
To be clear on this, authentication -is- possible, but only for web pages (Adaptive Cards don't need it). This auth would rely on the standard SSO Teams offers for Task Modules as well as Tabs. See here for intro guidance: https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso?tabs=dotnet, especially:
The SSO API also works in task modules that embed web content.
So really your question kind of becomes "how do I do SSO for web content in Teams". Here's a great video, which includes a link to text (blog) version of the content: https://devblogs.microsoft.com/microsoft365dev/lets-decode-single-sign-on-sso-in-microsoft-teams-tabs/. Here's a working sample, with both Node and DotNet backend options: https://adoption.microsoft.com/sample-solution-gallery/pnp-sp-dev-teams-sample-tab-sso. Note that the samples and docs generally focus on doing an OnBehalfOf (OBO) operation to call Graph, but the principle remains the same - you get a JWT token that you can pass back to your backend, which you can then validate. You can also, from the token, get user info for the logged in user.
From my comments: Looking at it as "Web inside Adaptive" and revisiting the sample project and your information it does seem the "CustomForm" razor page is initializing the Teams JavaScript SDK.
This DOES mean I can authenticate this content using the SSO as you mentioned.
I had only thought it would work in a TAB, not inside a bot card.Solved, follow the tabs javascript SDK guidance.

Read browser URL from Xamarin form android for custom OAuth code sent from the IDP in redirect URL

I am trying to implement custom OAuth login into my Xamarin application.
I am hitting the OAuth API from browser when a Login button is clicked.
It is redirecting to my custom OAuth authentication page and after initial authentication it sends an auth code in the URL of the auth.html from my domain page. I need to read that URL and process further.
My code in the button click :
var apiEndpoint = "https://auth.example.com/oauth2/authorize?response_type=code&client_id=myclientid&redirect_uri=https://example.com/apps/auth.html&state=STATE";
await Browser.OpenAsync("apiEndpoint", BrowserLaunchMode.SystemPreferred);
I need to read the code from the URL when is is returned from my domain redirect uri as below:
https://orion.lexmark.com/winapps/auth.html?code=12358123-2200-4ga6-a806-8f60f5636ac8&state=STATE
I am very new to the xamarin world, any help on this will be appriciated.
The most common way to do mobile OAuth is to use a Private URI Schene URL such as this, which will then invoke the app with the login response when it is returned to the browser:
com.mycompany. myapp:/callback
It is standard to also open the URL via an integrated form of the system browser - a Chrome Custom Tab on Android.
Developers usually also plug in the open source AppAuth libraries to do the tricky work of using OAuth messages correctly. This will be harder in Xamarin though, due to the extra layers.
I would recommend having a look at AppAuth and at least borrowing some ideas from it. My Android AppAuth Blog Post explaims a fast working setup.

Issue token to logged in user via spring

I have a Spring (3.2) based web app that a user can log into. The site will also provide an API secured via OAuth 2.0. My question then, is how do I go about generating a token for a logged in user?
The underlying idea here is that there will be a mobile app that opens up a web frame to the login page, which will eventually redirect to a url schema with an oauth token that the app will catch and then use for the api calls. Looking at the code for TokenEndpoint, I see that it defers token creation to a list of TokenGranter types. Should I be creating my own TokenGranter extended class, or am I looking at this all wrong?
I ended up writing a controller like this:
OAuthClientRequest request = OAuthClientRequest
.authorizationLocation(csOauthAuthorizeUrl)
.setClientId(csClientId)
.setRedirectURI(
UrlLocator.getBaseUrlBuilder().addSubpath(AUTH_CODE_HANDLER_URL).asUnEscapedString())
.setResponseType("code")
.buildQueryMessage();
UrlUtils.temporarilyRedirect(httpResponse, request.getLocationUri());
return null;
Then handling the code returned. My big problem here was that I had the /oauth/authorize endpoint set to use client credentials. Once I realized that tokens were being issued for the client ID instead of the user, it started to make sense.
So you want to use the Authorization Flow of OAuth. Spring has already support that, if you have configured the spring-security-oauth correctly, you just have to redirect the user/your mobile apps to /oauth/authorize?client_id=xxx&response_type=code this will redirect user to authorization page, if user has not login yet, it will redirect the user to login page then to the authorization page.
After the user completed the authorization process, it will redirect the user to an already registered redirect_url parameter with the authorization_code 'yourapp.com/callback?code=xxxx'.
Your application should exchange this authorization_code with the real token access to /oauth/token?grant_type=authorization_code&code=xxxx&client_id=xxxx&client_secret=xxxx
After that you will receive the token access that can be used to access the resource server.

What was I wrong when using Jersey Client to authenticate an Spring Security web application?

I have a web application which is protected by Spring Security Login Form authentication. Now I want to use Jersey Client to authenticate to my web pages and I think I should pass through login form as I do on a normal browser.
My client authentication code is as below
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/authentication-inmem/j_spring_security_check");
Form form = new Form();
form.param("j_username", "car");
form.param("j_password", "scarvarez");
Response response = target.request()
.post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
System.out.println(response.getStatus());
This code always produces 404 status code.
When I type the link http://localhost:8080/authentication-inmem/j_spring_security_check to my browser or just modify above code to an GET request. I could normally receive HTML code for authentication login form. Hence, I really don't know why this url is not found with an POST?
Hope you could show me what I am wrong here, and moreover, what I am doing is a proper way to authenticate to my server without using a browser?
I have found the answer, by default Jersey client will automatically redirect as soon as it receives a response with status is 3xx. (in this case it is 302).
Now, just turn off the feature by a bit configuration ahead, and I could get the status 302 display on my console.
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ClientProperties.FOLLOW_REDIRECTS, false);
Client client = ClientBuilder.newClient(clientConfig);

Resources