Scenario:
I have an API with .net core 2.2
On top my controller I authorize access using IdentityServer4 with an Attribute
Inside one of my endpoints I want to authorize access to a method only in some cases
I implemented resource based authorization inside my endpoint just like it's shown in microsoft documentation.
It didn't work.
I put a breakpoint inside my authorization handler and tried debugging, but when this handler should be called, it is not.
I mean that when the following line runs
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, "EditPolicy");
the Handler should be called, but that never happens.
Did anyone have the same problem?
So in the end the problem was due to the registration of the service in the startup.cs.
I was using TryAddScope, by changing to AddScope it worked fine.
Related
Set-up:
I have a web component (Angular 10) being used in an Angular 10 Application. The web component makes an Httpclient call to a web API to get some data to populate a menu dropdown. The web component was made using the standard methods to make a web component using Angular 10.
The web component is loaded through a script in the main client application. This is from the angular.json file for the parent application.
1."scripts":
[
"projects/web-component-test/src/assets/plugin.bundle.js"
]
and all works fine except we get a 401 error (unauthorized) since the end point requires the user to be logged in. By working fine, there are other controls that display as required just the the dropdown list, which gets it data from the API call does not get populated.
The flow:
User goes to website and then is prompted to log in (using keycloak Auth).
Application loads fine, except for the 401 error when the web component tries to load the menu items.
Http calls from the parent app work fine; the jwt token is added to the header for the call to the protected API. Calls from the child web component do not have the jwt token in the header, and thus fail with a 401 error.
httpinterceptor: we have an httpinterecptor on the main client application (the parent of the web control). Http calls that are made from the main app are routed through the interceptor where the token is attached to the header if needed.
Calls made from the child Web Component DO NOT hit the interceptor in the parent app?
Question:
How do I make call from the child web component route through the http interceptor in the parent so the token can be added.
Things I have tried:
I can get the web component to work fine if I do this:
When the parent loads I store the token in local storage
using an http interceptor on the web component, retrieve the token from local storage and use it.
** works, but I DO NOT want to store a secure token in local storage.
Pass the token in an attribute on the child component when the parent loads the child component
** again, I can get it to work, but not very secure.
A web component is an independent piece of code from your main codebase, so when you hit a request from the web component, your main app won't be able to catch those requests in the interceptor.
For me, one thing it worked was creating different Custom Events per every request:
doGetRequest
doPostRequest
doPutRequest
doDeleteRequest
Let me quickly guide you through one example of these events.
From the main app, I'm listening if any of these events are triggered:
this.popupEl.addEventListener('doPostRequest', (info: HTMLElementEventMap | any) => {
this.performHttpRequest(info.detail);
});
Notice that all the info sent from your web component, can be found in the property 'detail' your main app receives.
From the web component, I execute the following:
this.doPostRequest.emit({
url: 'the URL to hit',
endpointParams: {
user: 'my user',
password: '******',
}
});
Note: You can change the structure of the params to sent. It's totally up to you.
This will trigger the execution of the API in the main app, and as the request was executed from the main app, your interceptor will do its work and add whatever JWT you have there. Once the main app receives the response, you will need to set a new property in your web component to pass the response to it. Something like this:
this.popupEl.apiResponse = {
webComponentInfo: { ...infoReceivedFromYourWebComponent },
apiDetails: { ...ResponseFromYourBackend}
};
Finally, in your web component, add a new input that listen for the apiResponse attribute:
#Input()
set apiResponse(apiResponse: RequestParams) {
if (apiResponse.webComponentInfo.url === 'the URL to hit') {
// Do what you want in your web component, as you know exactly which URL just got executed.
}
}
This way, you let your main app continue doing its work with your interceptor and the web component won't need to handle the JWT or actually perform the requests.
One thing you may want to consider is not allowing the Delete request from your web component unless you and only you have full control over the web component. You wouldn't want anything that can perform a successful DELETE request to a very important API.
Hope this helps.
I have a Spring Boot application, that is using Spring Security with OAuth 2.0. Currently, it is operating against an Authentication Server based on Spring Example code. However, running our own Auth Server has always been a short-term target to facilitate development, not a long-term goal. We have been using the authorization_code grant type and would like to continue using that, irrespective of the Auth Server implementation.
I am attempting to make changes to use OAuth 2.0 Endpoints in Azure Active Directory, to behave as our Authentication Server. So far, I have a successful call to the /authorize endpoint. But the call to get the /token fails with an invalid request error. I can see the requests going out.
It appears that parameters that Azure states as mandatory are not being populated in the POST request. Looking at the Azure doco, it expects the client_id to be defined in the body of the message posted to the endpoint, and that is not added, by default, by Spring.
Can anyone point me in the right direction for how I can add fields to the Form Map that is used when constructing the Access Token request? I can see where the AccessTokenRequest object is being setup in OAuth2ClientConfiguration....
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
protected AccessTokenRequest accessTokenRequest(#Value("#{request.parameterMap}")
Map<String, String[]> parameters, #Value("#{request.getAttribute('currentUri')}")
String currentUri) {
DefaultAccessTokenRequest request = new DefaultAccessTokenRequest(parameters);
request.setCurrentUri(currentUri);
return request;
}
Should I be trying to define the map in a request.parameterMap spring property? If so, I'm not too sure how that works.
Or should I be using one of the interfaces defined in the AuthorizationServerConfigurerAdapter class?
I have the information to include when sending the AccessTokenRequest, I just don't know the best way to configure Spring to include it? Thanks for any help.
Actually, I found this out. I needed to change the client authentication scheme. Simply adding the following to my application properties added the client_id to the form....
security.oauth2.client.clientAuthenticationScheme=form
If you're using yaml, then yaml-ize it. Thank you Spring!
I'm looking at the source code for Microsoft.OWIN.Security.Google and am a bit confused and overwhelmed at how many classes there are to do such a simple thing (redirect, get a cookie, check it).
Can anyone explain how the various components fit together
Middleware
Extensions
etc
... so that I can write a custom provider
After some google-ing and trying different ideas in debugger I ended up with "copy-paste-edit" :)
here is a brief resume of classes
Extensions - nothing special, a helper:
// instead of using
app.Use(typeof(CustomAuthenticationMiddleware), app, options);
// you can use
app.UseCustomAuthentication(options);
Middlware - methods are used to attach authentication to owin pipeline
AuthenticationProvider - As I understand, this could be overriden outside, to be able to change some logic without rewriting whole thing. Has 2 methods:
Authenticated - is called when handler finishes all authentication in AuthenticationHandler.AuthenticateCoreAsync()
ReturnEndpoint which is called in AuthenticationHandler.InvokeAsync, just before external authetication.
But it appeared absolutely useless, when I tried to customize existing providers (google, facebook,...)
Handler - here is all the OAUTH2 functionality.
ApplyResponseChallengeAsync() - generates AuthorizationEndpoint URL and redirects useragent to authorization server
InvokeAsync() - handles the get to RedirectEndpoint (/signin-google or whatever was set up on authorization server) and returns the user to the starting controller(or callback). It is doing a redirect with all needed cookies set up
AuthenticateCoreAsync() - does all server side calls to authorization server. Creates all Identity.Claims necessary to create appropriate cookies before
I am trying to extract an id number from a URL using a web service so that it can be used as a parameter for a where clause in a select statement that produces data from a database based on the id number of a record. That data will then be passed back to the page to populate an element in a jQuery modal popup widow.
Everything works fine with a static id number (ex: string postid = "120"), but I don't know how to get the id number from the URL. I'm using Routing in .Net 4 and the method for accessing Routing in pages does not work in a web service. In pages I just do stuff like var id = RouteData.Values["id"]; and that gets the id, but when i did it in a web service I got an error:
CS0120: An object reference is required for the non-static field,
method, or property 'System.Web.Routing.RouteData.Values.get'
Summary:
I have web service accessed form a details page where I want to get RouteData for the page making the request. I want to do this just as easily as I can on a page using RouteData.Values which is just as easy as the now the obsolete Request.Querystring.
Now I am more confused because although I could easily add a new route for the web service I don't know I would call that using jQuery Ajax because of the webservice.asmx/webmethod syntax.
Right now I have URL: "../webservices/googlemaps.asmx/GetGoogleMap" in my jQuery Ajax, but that is not a real URL. It only exists in jQuery somewhere and the way to call the service using just JavaScript is no a real URL either, its webservice.webmethod() which in this case would be googlemaps.GetGoogleMap().
I will try registering a route for webservices/googlemaps.asmx/GetGoogleMap/postid, but I doubt it will work because GetGoogleMap is not a directory or a querystring.
Get current http request and use RequestContext property to get request context - it has current routing data. For example,
var id = HttpContext.Current.Request.RequestContext.RouteData.Values["id"];
In case of WCF based web service, make sure that service is participating in ASP.NET pipeline (see ASP.NET Compatibility)
EDIT: Sorry for misleading answer - the above will not work unless web service url is registered in routing engine. However, it may not solve your issue of retrieving the id - what kind of service implementation are you using? Are you making a GET request or POST request? Typically, web service handler (asmx) or WCF pipeline should convert GET/POST parameters to method parameters. Post your web service code and how you invoke it.
I got .asmx a web service on my app. I need to call a method from an other app to get statistics from my app. I need it to return XML. the call to the webmethod is done with javascript soap.
EDIT
I got the web service working. I can execute code and return a string but it stops there. When I try to pass parameters into the method it wont work and when I try to return a string[] or any other type it wont work either. any ideas? Is there something I need to do passing in parameters?
I think you could do two things.
One: enable [ScriptService] attribute on web method. This allows you to call the webservice
with javascript.
Example
Two: enable http-post/http-get webservice calls
How to enable