I am writing unit test for Authorization filter to validate the request/ token. However, it return null. not sure what is wrong.
https://programmium.wordpress.com/2020/04/30/unit-testing-custom-authorization-filter-in-net-core/
public class UserAuthorizationTests
{
private readonly Mock<ILogger<UserAuthorizationFilter>> _mocklogger;
private readonly Mock<IOptions<UserAuthorisationOptions>> _mockOption;
public UserAuthorizationTests()
{
_mocklogger = new Mock<ILogger<UserAuthorizationFilter>>();
_mockOption = new Mock<IOptions<UserAuthorisationOptions>>();
}
[Fact]
public void UserAuthorizationTest()
{
var httpContextMock = new Mock<HttpContext>();
httpContextMock.Setup(a => a.Request.Headers["UserAuthorization"]).Returns("test");
ActionContext fakeActionContext =
new ActionContext(httpContextMock.Object,
new Microsoft.AspNetCore.Routing.RouteData(),
new Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor());
AuthorizationFilterContext fakeAuthFilterContext =
new AuthorizationFilterContext(fakeActionContext,
new List<IFilterMetadata>());
UserAuthorizationFilter userAuthorizationFilter =
new UserAuthorizationFilter(_mockOption.Object, _mocklogger.Object);
userAuthorizationFilter.OnAuthorization(fakeAuthFilterContext);
Assert.NotEqual(typeof(UnauthorizedResult), userAuthorizationFilter.GetType());
}
}
you said “it return null”,it may help if you could describe it more clearly
I wrote the xunit test using Moq as below:
var httpContextMock = new Mock<HttpContext>();
httpContextMock.Setup(a => a.Request.Headers["Authorization"]).Returns("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiSmVmZmNreSIsIm5iZiI6MTY1MjA4NTg1NSwiZXhwIjoxNjUyMDg2MTU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDEifQ.cOpCN93U108Xr_km7GunxAJMrqx3LPnYAl3gLnXDW5M");
ActionContext fakeActionContext =new ActionContext(httpContextMock.Object, new Microsoft.AspNetCore.Routing.RouteData(),
new Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor());
JwksFilter jwksfilter = new JwksFilter();
AuthorizationFilterContext fakeAuthFilterContext =new AuthorizationFilterContext(fakeActionContext, new List<IFilterMetadata>() { });
jwksfilter.OnAuthorization(fakeAuthFilterContext);
Assert.Equal(typeof(UnauthorizedResult), fakeAuthFilterContext.Result.GetType());
Codes in my filter:
public void OnAuthorization(AuthorizationFilterContext context)
{
var jwks = context.HttpContext.Request.Headers["Authorization"].ToString();
var validateParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456")),
ValidateIssuer = true,
ValidIssuer = "http://localhost:5000",
ValidateAudience = true,
ValidAudience = "http://localhost:5001",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
var valiresult = ValidateToken(jwks, validateParameters);
if (valiresult == false)
{
context.Result = new UnauthorizedResult();
}
}
private static bool ValidateToken(string token, TokenValidationParameters validationParameters)
{
var tokenHandler = new JwtSecurityTokenHandler();
try
{
tokenHandler.ValidateToken(token, validationParameters, out var validatedToken);
return true;
}
catch (Exception e)
{
return false;
}
}
And the result:
Related
I want to use HttpClient to make requests using a certificate.
I generated a dev certificate using the following command
dotnet dev-certs https -ep dev_cert.pfx -p 1234
So I created an API to use that certificate. Here is the implementation.
public static class AuthenticationExtension
{
public static void ConfigureAuthetication(this IServiceCollection services)
{
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
var cert = new X509Certificate2(#"D:\dev_cert.pfx", "1234");
options.AllowedCertificateTypes = CertificateTypes.All;
options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
options.CustomTrustStore = new X509Certificate2Collection { cert };
options.RevocationMode = X509RevocationMode.NoCheck;
options.ValidateCertificateUse = false;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<ClientCertificateValidationService>();
if (validationService != null && validationService.ValidateCertificate(context.ClientCertificate))
{
Console.WriteLine("Success");
context.Success();
}
else
{
Console.WriteLine("invalid cert");
context.Fail("invalid cert");
}
return Task.CompletedTask;
},
OnChallenge = context =>
{
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
Console.WriteLine("Failed");
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
}
}
I added the Authorize attribute in the controller method
[HttpGet(Name = "GetWeatherForecast")]
[Authorize]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
I tested the request using Postman and it worked as expected.
Then, I created a console app to make the request using HttpClient. It failed always with the Forbidden Status code.
So I tested using the obsolete WebRequest. And It worked as expected.
Here is the implementation for that
using System.Net;
using System.Security.Cryptography.X509Certificates;
var handler = new HttpClientHandler();
X509Certificate2Collection certificates = new X509Certificate2Collection();
certificates.Import(#"D:\dev_cert.pfx", "1234", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
handler.ClientCertificates.AddRange(certificates);
using var client = new HttpClient(handler);
client.BaseAddress = new Uri("https://localhost:7148/");
try
{
var response = await client.GetAsync("weatherforecast/");
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
else
{
Console.WriteLine($"Failed {response.StatusCode}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Failed {ex}");
}
string host = #"https://localhost:7148/weatherforecast";
try
{
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
req.AllowAutoRedirect = true;
req.ClientCertificates = certificates;
req.Method = "GET";
WebResponse resp = req.GetResponse();
Stream stream = resp.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
string line = reader.ReadLine();
while (line != null)
{
Console.WriteLine(line);
line = reader.ReadLine();
}
}
stream.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
My question is... Since the WebRequest is obsolete what I can do to make the HttpClient work?
Thank you in Advance!
I am trying to do JWT Authentication, I have BlazorWASM (asp.net core hosted)
I have created a CustomAuthenticationStateProvider.
After logging in the user, I got this as expected:
But after re-rendering the use name disappears, but still I have access to authorised resources
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var savedToken = await _localStorage.GetItemAsync<string>("authToken");
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
var userInfo = await _localStorage.GetItemAsync<LoginResponse>("UserInfo");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt")));
}
public void MarkUserAsAuthenticated(string email)
{
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, email) }, "apiauth"));
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
NotifyAuthenticationStateChanged(authState);
}
Notice that I am only storing the token.
And this is the Login Method
public async Task<Response<LoginResponse>> Login(LoginRequest loginModel)
{
var loginAsJson = JsonSerializer.Serialize(loginModel);
var response = await _httpClient.PostAsync("api/Account/Login", new StringContent(loginAsJson, Encoding.UTF8, "application/json"));
var loginResult = JsonSerializer.Deserialize<Response<LoginResponse>>(await response.Content.ReadAsStringAsync(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (!response.IsSuccessStatusCode)
{
return loginResult;
}
await _localStorage.SetItemAsync("authToken", loginResult.Data.JWToken);
((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(loginModel.Email);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", loginResult.Data.JWToken);
return loginResult;
}
to be more specific, call GetAuthenticationStateAsync cause the same result (username disappears).
So what should I do?
I have implemented httpClientFactory but can't connect to the backend api using broken ssl.I tried a lot and i just got the task cancelled error -> HttpClient - A task was cancelled?
I have tried to set this
public static HttpClient getHttpClient()
{
if (_httpClient == null)
{
Uri baseUri = new Uri(Url.baseUrl);
if (baseUri.Scheme == "http")
{
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback =
(httpRequestMessage, cert, cetChain, policyErrors) =>
{
return true;
};
_httpClient = new HttpClient(handler);
}
else
{
_httpClient = new HttpClient();
}
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.BaseAddress = baseUri;
}
return _httpClient;
}
I'm using the WorkLightAuthenticator to validate User login.
But I need to return some parameters like userName, organozationID, among others. What would be the correct way to return this data?
I believe that would be the method createIdentity as exemple down. And to retrieve the data on the client?
/*Worklight Adapter*/
public class LoginModule implements WorkLightAuthLoginModule {
private String USERNAME;
private String PASSWORD;
public void init(Map<String, String> options) throws MissingConfigurationOptionException {
}
#SuppressWarnings("unchecked")
public boolean login(Map<String, Object> authenticationData) {
USERNAME = (String) authenticationData.get("username");
PASSWORD = (String) authenticationData.get("password");
InvocationResult invocationResult = callLoginAdapter(USERNAME, PASSWORD);
JSONObject jsonObject = invocationResult.toJSON();
HashMap<String, String> result = (HashMap<String, String>) jsonObject.get("result");
if(result != null){
return true;
} else {
HashMap<String, String> fault = (HashMap<String, String>) jsonObject.get("Fault");
String detail = fault.get("Detail");
throw new RuntimeException(detail);
}
}
public UserIdentity createIdentity(String loginModule) {
HashMap<String, Object> customAttributes = new HashMap<String, Object>();
customAttributes.put("AuthenticationDate", new Date());
customAttributes.put("userName", userExample);
customAttributes.put("organizationID", 1);
UserIdentity identity = new UserIdentity(loginModule, USERNAME, null, null, customAttributes, PASSWORD);
return identity;
}
public void logout() {
USERNAME = null;
PASSWORD = null;
}
public void abort() {
USERNAME = null;
PASSWORD = null;
}
#Override
public LoginModule clone() throws CloneNotSupportedException {
return (LoginModule) super.clone();
}
public InvocationResult callLoginAdapter(String user, String password){
DataAccessService service = WorklightBundles.getInstance().getDataAccessService();
String parameters = "['"+user+"','"+password+"']";
ProcedureQName procedureQName = new ProcedureQName("LoginAdapter", "getUserByLogin");
return service.invokeProcedure(procedureQName, parameters);
}
}
And AuthenticatorRealmChallengeHandler in client-side
/*AuthenticatorRealmChallengeHandler.js*/
var customAuthenticatorRealmChallengeHandler = WL.Client.createChallengeHandler("AuthenticatorRealm");
customAuthenticatorRealmChallengeHandler.isCustomResponse = function(response) {
console.log("**********************");
console.log(response.responseJSON);
if (!response || !response.responseJSON) {
return false;
}
if (response.responseJSON.authStatus)
return true;
else
return false;
};
customAuthenticatorRealmChallengeHandler.handleChallenge = function(response){
var authStatus = response.responseJSON.authStatus;
if (authStatus == "required"){
if (response.responseJSON.errorMessage){
currentPage.loginFail(response.responseJSON.errorMessage);
}
} else if (authStatus == "complete"){
currentPage.loadMaster();
customAuthenticatorRealmChallengeHandler.submitSuccess();
}
};
customAuthenticatorRealmChallengeHandler.submitLoginFormCallback = function(response) {
var isLoginFormResponse = customAuthenticatorRealmChallengeHandler.isCustomResponse(response);
if (isLoginFormResponse){
customAuthenticatorRealmChallengeHandler.handleChallenge(response);
}
};
$('#loginButton').bind('click', function () {
var reqURL = '/auth_request_url';
var options = {};
options.parameters = {
username : $('#userTextField').val(),
password : $('#passwordTextField').val()
};
options.headers = {};
customAuthenticatorRealmChallengeHandler.submitLoginForm(reqURL, options, customAuthenticatorRealmChallengeHandler.submitLoginFormCallback);
});
var attributes = WL.Client.getUserInfo("AuthenticatorRealm", "attributes");
Why am I getting this exception. The private key is not present in x509 certificate
This is to generate a username with nonce+ 2 binary security tokens(one for the usercertificate and one for the server).
My user certificate has a private key but the server certificate does not have one.
This is for Asymmetric binding.
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Text;
namespace MYEmedny
{
public class CustomCredentials : ClientCredentials
{
private X509Certificate2 clientAuthCert;
private X509Certificate2 clientSigningCert;
public CustomCredentials() : base() { }
public CustomCredentials(CustomCredentials other)
: base(other)
{
// other.clientSigningCert = SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "LMWARD");
clientSigningCert = other.clientSigningCert;
clientAuthCert = other.clientAuthCert;
}
protected override ClientCredentials CloneCore()
{
CustomCredentials scc = new CustomCredentials(this);
return scc;
}
public CustomCredentials(X509Certificate2 ClientAuthCert, X509Certificate2 ClientSigningCert)
: base()
{
clientAuthCert = ClientAuthCert;
clientSigningCert = ClientSigningCert;
}
public X509Certificate2 ClientAuthCert
{
get { return clientAuthCert; }
set { clientAuthCert = value; }
}
public X509Certificate2 ClientSigningCert
{
get { return clientSigningCert; }
set { clientSigningCert = value; }
}
public override SecurityTokenManager CreateSecurityTokenManager()
{
return new CustomTokenManager(this);
}
}
public class CustomTokenManager : ClientCredentialsSecurityTokenManager
{
private CustomCredentials custCreds;
public CustomTokenManager(CustomCredentials CustCreds)
: base(CustCreds)
{
custCreds = CustCreds;
}
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
try
{
if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
{
x509CustomSecurityTokenProvider prov;
object temp = null;
//TransportSecurityBindingElement secBE = null;
AsymmetricSecurityBindingElement secBE = null;
if (tokenRequirement.Properties.TryGetValue("http://schemas.microsoft.com/ws/2006/05/servicemodel/securitytokenrequirement/SecurityBindingElement", out temp))
{
//secBE = (TransportSecurityBindingElement)temp;
secBE = (AsymmetricSecurityBindingElement)temp;
}
if (secBE == null)
prov = new x509CustomSecurityTokenProvider(custCreds.ClientAuthCert);
else
prov = new x509CustomSecurityTokenProvider(custCreds.ClientSigningCert);
return prov;
}
}
catch (Exception ex)
{
throw ex;
}
return base.CreateSecurityTokenProvider(tokenRequirement);
}
public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version)
{
return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity10);
}
}
class x509CustomSecurityTokenProvider : SecurityTokenProvider
{
private X509Certificate2 clientCert;
public x509CustomSecurityTokenProvider(X509Certificate2 cert)
: base()
{
clientCert = cert;
}
protected override SecurityToken GetTokenCore(TimeSpan timeout)
{
return new X509SecurityToken(clientCert);
}
}
public class CustomTokenSerializer : WSSecurityTokenSerializer
{
public CustomTokenSerializer(SecurityVersion sv) : base(sv) { }
protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (token == null)
{
throw new ArgumentNullException("token");
}
if (token.GetType() == new UserNameSecurityToken("x", "y").GetType())
{
UserNameSecurityToken userToken = token as UserNameSecurityToken;
if (userToken == null)
{
throw new ArgumentNullException("userToken: " + token.ToString());
}
string tokennamespace = "wsse";
DateTime created = DateTime.Now;
string createdStr = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
string phrase = Guid.NewGuid().ToString();
string nonce = GetSHA1String(phrase);
string password = userToken.Password;
//string password = userToken.Password;
writer.WriteStartElement(tokennamespace, "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("wsu", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", token.Id);
writer.WriteElementString(tokennamespace, "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", userToken.UserName);
writer.WriteStartElement(tokennamespace, "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
writer.WriteValue(password);
writer.WriteEndElement();
writer.WriteStartElement(tokennamespace, "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
writer.WriteValue(nonce);
writer.WriteEndElement();
writer.WriteElementString(tokennamespace, "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", createdStr);
writer.WriteEndElement();
writer.Flush();
}
else
{
base.WriteTokenCore(writer, token);
}
}
protected string GetSHA1String(string phrase)
{
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
return Convert.ToBase64String(hashedDataBytes);
}
}//CustomTokenSerializer
}
This is how I am using it
private CustomBinding GetCustomBinding()
{
AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement
(
MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10
);
secBE.ProtectTokens = false;
X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
x509ProtectionParameters.RequireDerivedKeys = false;
x509ProtectionParameters.X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier;
x509ProtectionParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
//x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
secBE.MessageSecurityVersion = System.ServiceModel.MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
secBE.InitiatorTokenParameters = x509ProtectionParameters;
secBE.RecipientTokenParameters = x509ProtectionParameters;
secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
secBE.EnableUnsecuredResponse = true;
secBE.SetKeyDerivation(false);
secBE.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.TripleDesRsa15;
secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
secBE.ProtectTokens = true;
// secBE.in = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false );
secBE.EnableUnsecuredResponse = true;
secBE.IncludeTimestamp = false;
TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, System.Text.Encoding.UTF8);
HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
httpsBE.RequireClientCertificate = true;
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(secBE);
myBinding.Elements.Add(textEncBE);
myBinding.Elements.Add(httpsBE);
return myBinding;
}
ProxyGeneration.MHSClient proxy = new ProxyGeneration.MHSClient(GetCustomBinding(), new EndpointAddress(new Uri("https://service100.emedny.org:9047/MHService"), EndpointIdentity.CreateDnsIdentity("DPMedsHistory"), new AddressHeaderCollection()));
var vs = proxy.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
proxy.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName,"User");
proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "Server");
proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
proxy.Endpoint.Behaviors.Add(new CustomCredentials(GetCertificateFromStore("User"), GetCertificateFromStore("Server")));
proxy.ClientCredentials.UserName.UserName = "User1";
proxy.ClientCredentials.UserName.Password = "PWD";