When transferring security tokens to a WCF service, in which scenario should I use the following similar-sounding methods?
CreateChannelWithActAsToken
CreateChannelWithIssuedToken
CreateChannelWithOnBehalfOfToken
The documentation does not shed much light on the intended use. :-(
CreateChannelWithIssuedToken uses the current process token.
CreateChannelWithOnBehalfOfToken uses an external entity (not the current process). A service would use this to make a call "on behalf" of whomever called the service.
CreateChannelWithActAsToken uses both the current process and the external entity.
From Window Identity Foundation FAQ
From the WS-Trust procotol standpoint:
An ActAs RST element indicates
that the requestor wants a token that contains claims about two
distinct entities: the requestor, and an external entity represented
by the token in the ActAs element.
An OnBehalfOf RST element indicates that the requestor wants a token
that contains claims only about one entity: the external entity
represented by the token in the OnBehalfOf element.
The ActAs feature is typically used in scenarios that require
composite delegation, where the final recipient of the issued token
can inspect the entire delegation chain and see not just the client,
but all intermediaries.
Related
Hope everyone keeping safe,
I am trying to understand some of the abstractions in asp.net core authentication / authorization (and browsing the source code for additional insight).
There is an abstraction called "AuthenticationScheme" which seems to only bring in a ‘name’ property to the actual IAuthenticationHandler (which seems to be is the type that does the work).
I am trying to understand why asp.net has this the scheme abstraction, if the intent is just to give the handler a name, why not just include a name property in the handler's interface definition ?
To allow usage of the handler multiple times at least.
If you make an API that allows JWT Bearer tokens from two identity providers, then you might want to specify the JWT Bearer authentication handler twice.
And since each handler needs a unique name so we can invoke the right one, the developer must define those names.
I'm currently writing a service in Go where I need to deal with multiple tenants. I have settled on using the one database, shared-tables approach using a 'tenant_id' decriminator for tenant separation.
The service is structured like this:
gRPC server -> gRPC Handlers -
\_ Managers (SQL)
/
HTTP/JSON server -> Handlers -
Two servers, one gRPC (administration) and one HTTP/JSON (public API), each running in their own go-routine and with their own respective handlers that can make use of the functionality of the different managers. The managers (lets call one 'inventory-manager'), all lives in different root-level packages. These are as far as I understand it my domain entities.
In this regard I have some questions:
I cannot find any ORM for Go that supports multiple tenants out there. Is writing my own on top of perhaps the sqlx package a valid option?
Other services in the future will require multi-tenant support too, so I guess I would have to create some library/package anyway.
Today, I resolve the tenants by using a ResolveTenantBySubdomain middleware for the public API server. I then place the resolved tenant id in a context value that is sent with the call to the manager. Inside the different methods in the manager, I get the tenant id from the context value. This is then used with every SQL query/exec calls or returns a error if missing or invalid tenant id. Should I even use context for this purpose?
Resolving the tenant on the gRPC server, I believe I have to use the UnaryInterceptor function for middleware handling. Since the gRPC
API interface will only be accessed by other backend services, i guess resolving by subdomain is unneccessary here. But how should I embed the tenant id? In the header?
Really hope I'm asking the right questions.
Regards, Karl.
I cannot find any ORM for Go that supports multiple tenants out there. Is writing my own on top of perhaps the sqlx package a valid option?
ORMs in Go are a controversial topic! Some Go users love them, others hate them and prefer to write SQL manually. This is a matter of personal preference. Asking for specific library recommendations is off-topic here, and in any event, I don't know of any multi-tenant ORM libraries – but there's nothing to prevent you using a wrapper of sqlx (I work daily on a system which does exactly this).
Other services in the future will require multi-tenant support too, so I guess I would have to create some library/package anyway.
It would make sense to abstract this behavior from those internal services in a way which suits your programming and interface schemas, but there's no further details here to answer more concretely.
Today, I resolve the tenants by using a ResolveTenantBySubdomain middleware for the public API server. I then place the resolved tenant id in a context value that is sent with the call to the manager. Inside the different methods in the manager, I get the tenant id from the context value. This is then used with every SQL query/exec calls or returns a error if missing or invalid tenant id. Should I even use context for this purpose?
context.Context is mostly about cancellation, not request propagation. While your use is acceptable according to the documentation for the WithValue function, it's widely considered a bad code smell to use the context package as currently implemented to pass values. Rather than use implicit behavior, which lacks type safety and many other properties, why not be explicit in the function signature of your downstream data layers by passing the tenant ID to the relevant function calls?
Resolving the tenant on the gRPC server, I believe I have to use the UnaryInterceptor function for middleware handling. Since the gRPC API interface will only be accessed by other backend services, i guess resolving by subdomain is unneccessary here. But how should I embed the tenant id? In the header? [sic]
The gRPC library is not opinionated about your design choice. You can use a header value (to pass the tenant ID as an "ambient" parameter to the request) or explicitly add a tenant ID parameter to each remote method invocation which requires it.
Note that passing a tenant ID between your services in this way creates external trust between them – if service A makes a request of service B and annotates it with a tenant ID, you assume service A has performed the necessary access control checks to verify a user of that tenant is indeed making the request. There is nothing in this simple model to prevent a rogue service C asking service B for information about some arbitrary tenant ID. An alternative implementation would implement a more complex trust-nobody policy whereby each service is provided with sufficient access control information to make its own policy decision as to whether a particular request scoped to a particular tenant should be fulfilled.
I have a WCF service which uses a custom authentication and authorization manager.
Each time a client makes a call the authentication manager looks for a message header and uses the information to identify the user. The user gets created as an IPrincipal and placed into ServiceSecurityContext.Current.AuthorizationContext.Properties["Principal"].
I noticed on subsequent calls, where the users is different, the old user info is in the Current context. My service is tagged as PerCall. I am stumped on why the context is not getting cleared for every call.
Or is OperationContext different lifetime from SecurityContext?
If so any ideas on how to achieve what I described above? Thanks for help.
What is the best way to pass an existing SAML token from a website already authenticated via a passive STS?
We have built an Identity Provider which is issuing passive claims to the website for authentication. We have this working. Now we would like to add some WCF services into the mix - calling them from the context of the already authenticated web application. Ideally we would just like to pass the SAML token on without doing anything to it (i.e. adding new claims / re-signing). All of the examples I have seen require the ActAs sts implementation - but is this really necessary? This seems a bit bloated for what we want to achieve.
I would have thought a simple implementation passing the bootstrap token into the channel - using the CreateChannelActingAs or CreateChannelWithIssuedToken mechanism (and setting ChannelFactory.Credentials.SupportInteractive = false) to call the WCF service with the correct binding (what would that be?) would have been enough.
We are using the Fabrikam example code as reference, but as I say, think the ActAs functionality here is overkill for what we are trying to achieve.
What you need in this case is to insert the contents of your token into each outgoing message. If you look at the WIF Identity Training Toolkit they have an IssuedTokenHeader class that will facilitate this (along with the ClaimsIdentitySessionManager). These classes were built for Silverlight but, it doesn't change the solution they offer.
Here is an excerpt from the ClaimsIdentitySessionManager class.
using (OperationContextScope scope = new OperationContextScope(contextChannel))
{
IssuedTokenHeader header = new IssuedTokenHeader(this.TokenCache.GetTokenFromCache(serviceAppliesTo));
OperationContext.Current.OutgoingMessageHeaders.Add(header);
asyncOperation();
}
I especially need to get client's certificate used to call service's method. This is to react differently for different clients.
In your operation code, you can examine things like:
OperationContext.Current
or
ServiceSecurityContext.Current
but I'm not sure if you can access the actual client certificate from those.
The ServiceSecurityContext.Current.PrimaryIdentity will contain an IIdentity for the current caller - if it's NULL, then you're dealing with an anonymous call. Otherwise, the PrimaryIdentity will be one of several possible identity types, depending on how the calling user was authenticated - it could be a Windows identity, or something else - depending on your scenario.
See this blog post for a few more tidbits of information on X.509 and WCF.