dotnet / wcf

This repo contains the client-oriented WCF libraries that enable applications built on .NET Core to communicate with WCF services.
MIT License
1.72k stars 558 forks source link

Question: What do I do with ConfigureChannelFactory() and CreateChannelWithIssuedToken() in netstandard20? #4837

Open janniksam opened 2 years ago

janniksam commented 2 years ago

I am trying to migrate a project from .NET Framework 4.8 to .NET Standard 2.0 right now.

With the newest nuget packages "4.10.0-preview1.22261.2" I'm getting very close of getting rid of all the errors right now. The WSChannelFactory etc are mostly included in the latest preview, but there are two errors left in my code in the following method:

        public T GetChannel()
        {
        using (m_log.CreateScope(nameof(GetChannel)))
            {
                ChannelFactory<T> channelFactory = CreateChannelFactoryFromConfiguration();
                channelFactory.ConfigureChannelFactory(); // <---------------------------this
                if (m_securityToken != null)
                {
                    m_log.WriteInfo("Creating channel with issued token");
                    return channelFactory.CreateChannelWithIssuedToken(m_securityToken); // <---------------------------and this
                }
                m_log.WriteInfo("Creating channel");
                T channel = channelFactory.CreateChannel();
                ClientChannelExtension clientChannelExtension = new() 
                {ServiceEndpoint = channelFactory.Endpoint};
                ((IClientChannel)channel).Extensions.Add(clientChannelExtension);
                return channel;
            }
        }

Apparently both ConfigureChannelFactory and CreateChannelWithIssuedToken are part of the Microsoft.IdentityModel, which is a .NET Framework nuget package.

Are there alternatives that I can do?

StephenMolloy commented 2 years ago

@mconnew, is there a viable workaround for this? @imcarolwang, can you work on this with Matt for 7.0?

mconnew commented 2 years ago

Until we add the api, there is a way to do this, but it does require quite a bit of boiler plate code. You need to have a custom derived ClientCredentials class, which will provide a custom ClientCredentialsSecurityTokenManager, which will provide a custom SecurityTokenProvider which will return a custom SecurityToken which will hold your issued token. There's a lot of details in that brief description and it's a non-trivial amount of work. You could probably copy the source code of the System.ServiceModel.Federation project and modify it to not go get a token using WSTrust from an STS but instead use one that you configure yourself as it has all that plumbing code already written.
So you have 2 options, wait for us to ship this, or use the extensibility in WCF to provide an equivalent implementation. Let me know if you need more guidance on the DIY approach.

janniksam commented 2 years ago

Until we add the api, there is a way to do this, but it does require quite a bit of boiler plate code. You need to have a custom derived ClientCredentials class, which will provide a custom ClientCredentialsSecurityTokenManager, which will provide a custom SecurityTokenProvider which will return a custom SecurityToken which will hold your issued token. There's a lot of details in that brief description and it's a non-trivial amount of work. You could probably copy the source code of the System.ServiceModel.Federation project and modify it to not go get a token using WSTrust from an STS but instead use one that you configure yourself as it has all that plumbing code already written. So you have 2 options, wait for us to ship this, or use the extensibility in WCF to provide an equivalent implementation. Let me know if you need more guidance on the DIY approach.

I tried to copy everything from the current .NET Framework 4.5(?) Microsoft.IdentityModel implementation but I quickly came to the conclusion that it's way too much to copy and stopped the approach. (especially if you don't know what you're doing ;-)

It's not time-sensitive, it's just that it's the only thing, that's holding our companies application service back from being ported from WCF to GRPC right now.

To be more specific and to let you know the whole background, our WCF application currently consumes 3 more WCF services developed by another company that we can't modify:

Since they are still working on their internal interface to be converted to GRPC, I didn't want to wait for their external interface to be GRPC, which will likely take another 1-2 years, in which we could start migrating our own WCF service to GRPC 👍

thuannguy commented 2 years ago

Until we add the api, there is a way to do this, but it does require quite a bit of boiler plate code. You need to have a custom derived ClientCredentials class, which will provide a custom ClientCredentialsSecurityTokenManager, which will provide a custom SecurityTokenProvider which will return a custom SecurityToken which will hold your issued token. There's a lot of details in that brief description and it's a non-trivial amount of work.

Just in case anyone has the same need: I can confirm that this workaround works. I managed to make such an implementation a couple of months ago. Code itself is not too complex. The hard part is at reading through WCF source code and understanding how those classes work.

Skoucail commented 2 years ago

@thuannguy

Any chance you have the code available somewhere? I'm trying to get claims with WS-Trust from a federated ADFS setup. This means I request a SymmetricKey from ADFS1. And then pass the token I received to ADFS2 to receive a BearerKey. In the old code we used CreateChannelWithIssuedToken. But from what I can find this isn't provided yet.

Any help would be very welcome!

thuannguy commented 2 years ago

@Skoucail Perhaps this can help? https://github.com/dotnet/wcf/issues/4866 Code that I have written is not ready yet, and it is my customers who decide if they want to publish it.

Skoucail commented 2 years ago

@thuannguy Thanks for your reply, i found that code and tried to use it. But for some reason i cant get it to work. I think im missing something in how i need to combine the ws-trust call and the samlprovider. I tried passing it to WSTrustChannelClientCredentials but then im just getting errors. I tried using it directly but then im just getting the same saml token.

Can you plz put me on the right path on how i should use the code from #4866?

eiki25 commented 2 years ago

@mconnew, @thuannguy I followed your workaround for replacing CreateChannelWithIssuedToken in Full framework into NET 6

        /* Old
        return ChannelFactory.CreateChannelWithIssuedToken(token);
        */

        // New
        SamlProvider.SamlClientCredentials credentials = new SamlProvider.SamlClientCredentials(token);
        ChannelFactory.Endpoint.EndpointBehaviors.Remove(typeof(ClientCredentials));
        ChannelFactory.Endpoint.EndpointBehaviors.Add(credentials);
        ChannelFactory.CreateChannel();

`

Only problem is that SamlSecurityTokenProvider requires that you implement GetTokenCore which we don´t have any implementation for. Any ideas?

mconnew commented 2 years ago

You would return the token than you normally pass to CreateChannelWithIssuedToken. I think you might need to wrap it, I'm not sure. Here's the implementation of the SecurityTokenProvider that is used in this scenario on .NET Framework. As you can see, it either just returns the original security token, or it wraps it in another token which includes a policy.

eiki25 commented 2 years ago

@mconnew worked like a charm, thanks. Is there any plans of making a similar extension method for ChannelFactory for this like in the old framework?