| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Net; |
| | | 6 | | using System.Security.Principal; |
| | | 7 | | using System.Threading; |
| | | 8 | | using System.Threading.Tasks; |
| | | 9 | | using CoreWCF.IdentityModel.Selectors; |
| | | 10 | | using CoreWCF.IdentityModel.Tokens; |
| | | 11 | | using CoreWCF.Security; |
| | | 12 | | using CoreWCF.Security.Tokens; |
| | | 13 | | |
| | | 14 | | namespace CoreWCF.Channels |
| | | 15 | | { |
| | | 16 | | internal static class TransportSecurityHelpers |
| | | 17 | | { |
| | | 18 | | private static async Task<T> GetTokenAsync<T>(SecurityTokenProvider tokenProvider, CancellationToken token) |
| | | 19 | | where T : SecurityToken |
| | | 20 | | { |
| | 12 | 21 | | SecurityToken result = await tokenProvider.GetTokenAsync(token); |
| | 12 | 22 | | if ((result != null) && !(result is T)) |
| | | 23 | | { |
| | 0 | 24 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( |
| | 0 | 25 | | SR.InvalidTokenProvided, tokenProvider.GetType(), typeof(T)))); |
| | | 26 | | } |
| | 12 | 27 | | return result as T; |
| | 12 | 28 | | } |
| | | 29 | | |
| | | 30 | | // used by server WindowsStream security (from Open) |
| | | 31 | | public static async Task<(NetworkCredential, bool)> GetSspiCredentialAsync(SecurityTokenManager credentialProvid |
| | | 32 | | SecurityTokenRequirement sspiTokenRequirement, CancellationToken token) |
| | | 33 | | { |
| | 12 | 34 | | bool extractGroupsForWindowsAccounts = TransportDefaults.ExtractGroupsForWindowsAccounts; |
| | 12 | 35 | | NetworkCredential result = null; |
| | | 36 | | |
| | 12 | 37 | | if (credentialProvider != null) |
| | | 38 | | { |
| | 12 | 39 | | SecurityTokenProvider tokenProvider = credentialProvider.CreateSecurityTokenProvider(sspiTokenRequiremen |
| | 12 | 40 | | if (tokenProvider != null) |
| | | 41 | | { |
| | 12 | 42 | | await SecurityUtils.OpenTokenProviderIfRequiredAsync(tokenProvider, token); |
| | 12 | 43 | | bool success = false; |
| | | 44 | | try |
| | | 45 | | { |
| | | 46 | | TokenImpersonationLevel dummyImpersonationLevel; |
| | | 47 | | bool dummyAllowNtlm; |
| | 12 | 48 | | (result, extractGroupsForWindowsAccounts, dummyImpersonationLevel, dummyAllowNtlm) = await GetSs |
| | | 49 | | |
| | 12 | 50 | | success = true; |
| | 12 | 51 | | } |
| | | 52 | | finally |
| | | 53 | | { |
| | 12 | 54 | | if (!success) |
| | | 55 | | { |
| | 0 | 56 | | SecurityUtils.AbortTokenProviderIfRequired(tokenProvider); |
| | | 57 | | } |
| | | 58 | | } |
| | 12 | 59 | | await SecurityUtils.CloseTokenProviderIfRequiredAsync(tokenProvider, token); |
| | | 60 | | } |
| | 12 | 61 | | } |
| | | 62 | | |
| | 12 | 63 | | return (result, extractGroupsForWindowsAccounts); |
| | 12 | 64 | | } |
| | | 65 | | |
| | | 66 | | // core Cred lookup code |
| | | 67 | | private static async Task<(NetworkCredential, bool, TokenImpersonationLevel, bool)> GetSspiCredentialAsync(SspiS |
| | | 68 | | { |
| | 12 | 69 | | NetworkCredential credential = null; |
| | 12 | 70 | | bool extractGroupsForWindowsAccounts = TransportDefaults.ExtractGroupsForWindowsAccounts; |
| | 12 | 71 | | TokenImpersonationLevel impersonationLevel = TokenImpersonationLevel.Identification; |
| | 12 | 72 | | bool allowNtlm = ConnectionOrientedTransportDefaults.AllowNtlm; |
| | | 73 | | |
| | 12 | 74 | | if (tokenProvider != null) |
| | | 75 | | { |
| | 12 | 76 | | SspiSecurityToken token = await GetTokenAsync<SspiSecurityToken>(tokenProvider, cancellationToken); |
| | 12 | 77 | | if (token != null) |
| | | 78 | | { |
| | 12 | 79 | | extractGroupsForWindowsAccounts = token.ExtractGroupsForWindowsAccounts; |
| | 12 | 80 | | impersonationLevel = token.ImpersonationLevel; |
| | 12 | 81 | | allowNtlm = token.AllowNtlm; |
| | 12 | 82 | | if (token.NetworkCredential != null) |
| | | 83 | | { |
| | 0 | 84 | | credential = token.NetworkCredential; |
| | 0 | 85 | | SecurityUtils.FixNetworkCredential(ref credential); |
| | | 86 | | } |
| | | 87 | | } |
| | | 88 | | } |
| | | 89 | | |
| | | 90 | | // Initialize to the default value if no token provided. A partial trust app should not have access to the |
| | | 91 | | // default network credentials but should be able to provide credentials. The DefaultNetworkCredentials |
| | | 92 | | // getter will throw under partial trust. |
| | 12 | 93 | | if (credential == null) |
| | | 94 | | { |
| | 12 | 95 | | credential = CredentialCache.DefaultNetworkCredentials; |
| | | 96 | | } |
| | | 97 | | |
| | 12 | 98 | | return (credential, extractGroupsForWindowsAccounts, impersonationLevel, allowNtlm); |
| | 12 | 99 | | } |
| | | 100 | | |
| | | 101 | | public static SecurityTokenRequirement CreateSspiTokenRequirement(string transportScheme, Uri listenUri) |
| | | 102 | | { |
| | 12 | 103 | | RecipientServiceModelSecurityTokenRequirement tokenRequirement = new RecipientServiceModelSecurityTokenRequi |
| | 12 | 104 | | { |
| | 12 | 105 | | TransportScheme = transportScheme, |
| | 12 | 106 | | RequireCryptographicToken = false, |
| | 12 | 107 | | ListenUri = listenUri, |
| | 12 | 108 | | TokenType = ServiceModelSecurityTokenTypes.SspiCredential |
| | 12 | 109 | | }; |
| | 12 | 110 | | return tokenRequirement; |
| | | 111 | | } |
| | | 112 | | |
| | | 113 | | public static SecurityTokenAuthenticator GetCertificateTokenAuthenticator(SecurityTokenManager tokenManager, str |
| | | 114 | | { |
| | 5 | 115 | | RecipientServiceModelSecurityTokenRequirement clientAuthRequirement = new RecipientServiceModelSecurityToken |
| | 5 | 116 | | { |
| | 5 | 117 | | TokenType = SecurityTokenTypes.X509Certificate, |
| | 5 | 118 | | RequireCryptographicToken = true, |
| | 5 | 119 | | KeyUsage = SecurityKeyUsage.Signature, |
| | 5 | 120 | | TransportScheme = transportScheme, |
| | 5 | 121 | | ListenUri = listenUri |
| | 5 | 122 | | }; |
| | 5 | 123 | | return tokenManager.CreateSecurityTokenAuthenticator(clientAuthRequirement, out SecurityTokenResolver dummy) |
| | | 124 | | } |
| | | 125 | | |
| | | 126 | | public static Uri GetListenUri(Uri baseAddress, string relativeAddress) |
| | | 127 | | { |
| | 17 | 128 | | Uri fullUri = baseAddress; |
| | | 129 | | |
| | | 130 | | // Ensure that baseAddress Path does end with a slash if we have a relative address |
| | 17 | 131 | | if (!string.IsNullOrEmpty(relativeAddress)) |
| | | 132 | | { |
| | 0 | 133 | | if (!baseAddress.AbsolutePath.EndsWith("/", StringComparison.Ordinal)) |
| | | 134 | | { |
| | 0 | 135 | | UriBuilder uriBuilder = new UriBuilder(baseAddress); |
| | 0 | 136 | | FixIpv6Hostname(uriBuilder, baseAddress); |
| | 0 | 137 | | uriBuilder.Path = uriBuilder.Path + "/"; |
| | 0 | 138 | | baseAddress = uriBuilder.Uri; |
| | | 139 | | } |
| | | 140 | | |
| | 0 | 141 | | fullUri = new Uri(baseAddress, relativeAddress); |
| | | 142 | | } |
| | | 143 | | |
| | 17 | 144 | | return fullUri; |
| | | 145 | | } |
| | | 146 | | |
| | | 147 | | // Moved from TcpChannelListener |
| | | 148 | | internal static void FixIpv6Hostname(UriBuilder uriBuilder, Uri originalUri) |
| | | 149 | | { |
| | 0 | 150 | | if (originalUri.HostNameType == UriHostNameType.IPv6) |
| | | 151 | | { |
| | 0 | 152 | | string ipv6Host = originalUri.DnsSafeHost; |
| | 0 | 153 | | uriBuilder.Host = string.Concat("[", ipv6Host, "]"); |
| | | 154 | | } |
| | 0 | 155 | | } |
| | | 156 | | } |
| | | 157 | | } |