In our company we try to start using oauth2.0 with our Azure AD Tenant using vue.js as frontend and vert.x services on the backend.
The idea would be that i want to
If i call our vert.x service with the jwt which we got from Azure AD i got a runtime exception saying: "Not enough or too many segments". The JWT has 3 segments like expected. This is how i create the AzureADAuth:
OAuth2ClientOptions opts = new OAuth2ClientOptions();
opts.setFlow(OAuth2FlowType.AUTH_JWT);
OAuth2Auth auth = AzureADAuth.create(vertx,"{{application-id}}","{{secret}}","{{tenant-id}}", opts);
Inside my handler i try to authenticate:
HttpServerRequest request = context.request();
String authorization = request.headers().get(HttpHeaders.AUTHORIZATION);
String[] parts = authorization.split(" ");
scheme = parts[0];
token = parts[1];
JsonObject creds = new JsonObject();
creds.put("token_type", scheme);
creds.put("access_token", token);
authProvider.authenticate(creds,userAsyncResult -> {
if(userAsyncResult.succeeded()){
context.next();
} else {
context.fail(401);
}
});
So after i figured out that i need to add a jwk i tried to use the AzureADAuth.discover method.
My code looks like this:
OAuth2ClientOptions optsDisc = new OAuth2ClientOptions();
optsDisc.setSite("https://login.windows.net/{tenant-id}");
optsDisc.setClientID("{application-id}");
AzureADAuth.discover(vertx, optsDisc,res -> {
if (res.succeeded()) {
if(log.isDebugEnabled()) {
log.debug("Discover succeeded.");
}
} else {
log.error("Discover failed.");
}
});
Running this code causes a "Discover failed" with the following message:
java.lang.RuntimeException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
So my question is how do i authenticate my user with my given bearer token with vert.x?
I obviously had a version conflict here.
I set all my dependencies to 3.6.2 and now it works. Just took me a bit to figure out how to handle the discovery and that i don't need to create a new OAuth2Auth object with AzureAdAuth after the discovery.
For future reference:
OAuth2ClientOptions optsDisc = new OAuth2ClientOptions();
opts.setClientID("{client-id}");
AzureADAuth.discover(vertx, opts,res -> {
if (res.succeeded()) {
//use res.result() to access the through discovery already created OAuth2Auth Object
log.debug("Discover succeeded.");
} else {
log.error("Discover failed.");
}
})
Related
When I try to verify the Firebase jwt token in my Spring Boot backend application, I get the following error:
Failed to verify the signature of Firebase ID token. See
https://firebase.google.com/docs/auth/admin/verify-id-tokens for
details on how to retrieve an ID token.
In the client (Flutter) I log the jwt as follows:
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
UserCredential authResult = await _auth.signInWithCredential(credential);
_user = authResult.user;
logger.i(await _user.getIdToken()); // Print jwt
I send the jwt that gets logged to my backend through the Authorization header as a bearer token.
Using Spring security (it doesn't matter), I just perform the following check:
FirebaseToken decoded = FirebaseAuth.getInstance().verifyIdToken(token);
My firebase app init config is pretty standard (env variable pointing to config.json is set):
#Primary
#Bean
public void firebaseInit() throws IOException {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.build();
if (FirebaseApp.getApps().isEmpty()) {
FirebaseApp.initializeApp(options);
}
}
After debugging, following method throws in class RSASignature (package package sun.security.rsa):
#Override
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
if (publicKey == null) {
throw new SignatureException("Missing public key");
}
try {
if (sigBytes.length != RSACore.getByteLength(publicKey)) {
throw new SignatureException("Signature length not correct: got " +
sigBytes.length + " but was expecting " +
RSACore.getByteLength(publicKey));
}
sigBytes length is 113, whereas it expects to be 256.
Perhaps I'm doing something wrong though...
My God... the logger that I used in dart decided to just cap the jwt string so the jwt was incomplete.
Now I get a message 'forbidden' happy joy. But the previous error has been resolved.
Edit 'Forbidden' was consequence of a minor Spring Boot issue (adding roles to authorities).
It now works as expected.
Azure's Policy service comes with many built-in policies. They can be accessed using Azure's Java SDK and the Azure Resource Manager. The definition of a specific policy can be acquired using the getByName() method in the SDK.
The code looks like this:
AzureResourceManager azureResourceManager = AzureResourceManager
.authenticate(credential, profile)
.withSubscription("<my-subscription-id>");
PolicyDefinition policyDefinition = azureResourceManager.policyDefinitions().getByName("<name>");
To test this code, I went to the console to find the name of a pre-built policy. I found two different names, one in the text:
and a different one in the definition:
However, trying to retrieve the policy definition using either of these names results in the same error:
Status code 404, The policy definition 'Audit VMs that do not use managed disks' could not be found.
and
Status code 404, The policy definition '06a78e20-9358-41c9-923c-fb736d382a4d' could not be found
Question: What name is this method looking for? Or is there a better way to retrieve a policy definition?
If you want to get one build_in policy in java application, you can use the method PolicyClientImpl.getPolicyDefinitions().getBuiltIn() in the package com.azure.resourcemanager.resources. Besides, please note that the name of build-in policy is guide.
For example
install sdk
<dependency>
<groupId>com.azure.resourcemanager</groupId>
<artifactId>azure-resourcemanager-resources</artifactId>
<version>2.1.0</version>
</dependency>
Code
String clientId="";
String clientSecret="";
String tenant="";
String subId="";
AzureProfile profile = new AzureProfile(tenant,subId, AzureEnvironment.AZURE);
TokenCredential credential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
.authorityHost(profile.getEnvironment().getActiveDirectoryEndpoint())
.tenantId(tenant)
.build();
PolicyClientImpl policyClient= new PolicyClientBuilder()
.pipeline(HttpPipelineProvider.buildHttpPipeline(credential,profile))
.endpoint(profile.getEnvironment().getResourceManagerEndpoint())
.subscriptionId(profile.getSubscriptionId())
.buildClient();
PolicyDefinitionInner policy = policyClient.getPolicyDefinitions().getBuiltIn("04d53d87-841c-4f23-8a5b-21564380b55e");
System.out.println(policy.policyType());
System.out.println(policy.description());
In the end, I wound up using the REST API to get the policy definition when I all know is the policy definition name. Note that I had to use a one call to get built-in policies and another to get custom policies, which is painful since I didn't know a priori which type I had. I used OkHttpClient to handle the heavy lifting. Here's my solution:
Boolean itMightBeACustomPolicy = false;
OkHttpClient builtinPolicyDefinitionHttpClient = new OkHttpClient();
String builtinPolicyDefinitionUrl = "https://management.azure.com/providers/Microsoft.Authorization/policyDefinitions/"
+ policyState.getString("policyDefinitionName") // This is what I know
+ "?api-version=2020-09-01";
Request builtinPolicyDefinitionRequest = new Request.Builder()
.url(builtinPolicyDefinitionUrl)
.addHeader("Authorization", "Bearer " + token)
.get()
.build();
String policyDefinitionJson = "";
try
{
Response builtinPolicyDefinitionResponse = builtinPolicyDefinitionHttpClient.newCall(builtinPolicyDefinitionRequest).execute();
if(builtinPolicyDefinitionResponse.isSuccessful())
{
// It's a built-in policy definition
policyDefinitionJson = builtinPolicyDefinitionResponse.body().string();
}
else
{
// Let's try for a custom definition
// I do this separately to keep the try..catch unique.
itMightBeACustomPolicy = true;
}
}
catch (IOException e)
{
e.printStackTrace(); // TODO Handle this...
}
if(itMightBeACustomPolicy)
{
OkHttpClient customPolicyDefinitionHttpClient = new OkHttpClient();
String customPolicyDefinitionUrl = "https://management.azure.com/subscriptions/"
+ subscriptionId
+ "/providers/Microsoft.Authorization/policyDefinitions/"
+ policyState.getString("policyDefinitionName") // This is what I know
+ "?api-version=2020-09-01";
Request customPolicyDefinitionRequest = new Request.Builder()
.url(customPolicyDefinitionUrl)
.addHeader("Authorization", "Bearer " + token)
.get()
.build();
try
{
Response customPolicyDefinitionResponse = customPolicyDefinitionHttpClient.newCall(customPolicyDefinitionRequest).execute();
if(customPolicyDefinitionResponse.isSuccessful())
{
policyDefinitionJson = customPolicyDefinitionResponse.body().string();
}
else
{
// Not sure what it is. Let's assume there are no policy definitions available.
// So do nothing here for now.
}
}
catch (IOException e)
{
e.printStackTrace(); // TODO Handle this...
}
}
// Wherever we got the policy definition from, let's parse it and gather data.
// NOTE: This design assumes that the JSON for built-in and custom are (nearly) identical.
// That might be wrong.
if(!policyDefinitionJson.isEmpty())
{
JSONObject policyDefinitionRootObject = new JSONObject(policyDefinitionJson);
// Do something with the resulting JSON
System.out.println(policyDefinitionRootObject.getJSONObject("properties").getString("policyType"));
System.out.println(policyDefinitionRootObject.getJSONObject("properties").getString("description"));
System.out.println(policyDefinitionRootObject.getJSONObject("properties").getString("displayName"));
}
Note: "OkHttp performs best when you create a single OkHttpClient instance and reuse it for all of your HTTP calls." So I need to do some re-factoring still to avoid creating multiple clients.
I am trying to fetch google contacts for a user via oAuth2 mechanism. I am following this tutorial - https://developers.google.com/identity/sign-in/web/server-side-flow
I have javascript code that calls start() on pageload -
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: 'SOME_CLEINT_ID',
scope: 'https://www.googleapis.com/auth/contacts.readonly'
});
});
}
and
auth2.grantOfflineAccess().then(signInCallback);
and then -
function signInCallback(authResult) {
if (authResult['code']) {
var callback = function(data){
data = JSON.parse(data);
console.log(data);
};
callAjax({action: 'saveGmailAuth', gaccesscode: authResult['code']}, callback, true);
} else {
// There was an error.
}
}
This front end code calls my backend Java web servlet, which tries to get access token -
String authCode = request.getParameter("gaccesscode");
String REDIRECT_URI = "";
String CLIENT_SECRET_FILE = "G:/eclipse_proj/GoogleContacts/CLIENT_JSON_FILE.json";
GoogleClientSecrets clientSecrets;
try {
clientSecrets = GoogleClientSecrets.load(JacksonFactory.getDefaultInstance(),
new FileReader(CLIENT_SECRET_FILE));
REDIRECT_URI = clientSecrets.getDetails().getRedirectUris().get(0);
GoogleAuthorizationCodeTokenRequest tokenRequest = new GoogleAuthorizationCodeTokenRequest(new NetHttpTransport(),
JacksonFactory.getDefaultInstance(), "https://www.googleapis.com/oauth2/v3/token",
clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret(), authCode,
REDIRECT_URI);
GoogleTokenResponse tokenResponse = tokenRequest.execute();
String accessToken = tokenResponse.getAccessToken();
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Every time I try this java code, every time it gives me error at tokenRequest.execute() -
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "redirect_uri_mismatch",
"error_description" : "Bad Request"
}
With REDIRECT_URI as empty string, it give another error saying - redirect_uri_not_provided.
I tried it with both "https://www.googleapis.com/oauth2/v3/token" and "https://www.googleapis.com/oauth2/v4/token"
I need help figuring this out. What am I doing wrong here?
My redirect URI is - http://localhost:8080/GoogleContacts/Callback in both json file and in developer console for oauth2.
For redirect_uri in using Google APIs,go to your Google Dev console and type what you see as is:
//you can use any port you want
http:localhost:8080/oauth2callback
oauth2callback is the key ingredient.
I am using the code below to 1) Login the user on keycloak, 2) Verify if the user has the specific role to access some resource.
JsonObject keycloakJson = new JsonObject()
.put("realm", "OQM") // (1)
.put("realm-public-key", "MIIBIwercerewrcewrc7BAij3P+Nz76opTVlhWijnIGefnBygViDrUdxS/nZSDTkXrFnKy2lpNZyecWrNVD6Zs6w65pBa60zDWODkuIqE6LbbfwHBs5RyvuzAFRtRFbieZub8x4suzN5pJOUPWdtgWqQasdawercwerewvrewrvewrcwxewrvbewvrxw9k+TPKGdf3e9QXL9FGG/9084+6Z8RSZ4JL4v5YqVtpDyohf9MPJwn/i46KcAYzgleJFFCqwuPry8CEzafqXVlzIEkSqwIDAQAB") // (2)
.put("auth-server-url", "http://152.18.17.63:8080/auth")
.put("ssl-required", "external")
.put("resource", "oqm") // (3)
.put("credentials", new JsonObject().put("secret", "2343253252-c8f1-42b2-866c-87a2a7ff95f6")); // (4)
OAuth2Auth oauth2 = KeycloakAuth.create(vertx, OAuth2FlowType.PASSWORD, keycloakJson);
JsonObject tokenConfig = new JsonObject().put("username", "dummyUser").put("password", "password").put("scope", "modify-account view-account");
oauth2.getToken(tokenConfig, res -> {
if (res.failed()) {
rc.response().setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()).end();
} else {
AccessToken token = (AccessToken)res.result();
token.isAuthorised("ReleaseOrders", handler -> {
if(handler.result()) {
HttpServerResponse response = VerticleUtils.buildOKHeaders(rc);
response.end(Json.encodePrettily(token.principal()));
}
else {
VerticleUtils.notAuthorized(rc);
}
});
}
});
However, I need to get a list of roles user is authorized for. I can see the roles in a property of the
AccessToken object returned, but since its access is private I cant access them.
Currently you can only get the full token from the principal() method call. For 3.5.1 we're are working on exposing the token from the AcessToken object.
Have been struggling for last few days with this error Authentication of type {http://service.soap.xcompany.com}AuthenticationHeader had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id while invoking a service call from a C# WCF client (targeting .Net 4.5 framework) to a Java Soap Service hosted externally with end-to-end encryption (both client and service certificates are used). When I tested the service using SoapUI with a JKS file, request was processed successfully.
So to see what's difference between the two requests, I did the followings:
Used Fiddler Inspector to capture two requests, one from SoapUI which was successful and one from C# which failed with 500 error
Extracted these two Xml messages into two C# classes (named them RequestByJava and RequestByDotNet, respectively) using the VS2017 feature Edit/Paste Special/Paste Xml as Classes.
Use XmlSerializer to de-serialize the two requests into the two objects of the types created in 2) and compared their properties.
With the Soap error message in mind, I narrowed down the difference between two Authentication headers - interestingly there is one extra property "Id" in the RequestByDotNet object whereas the RequestByJava object does not have. And the 500 Soap error message seemed to indicate that there was a schema validation error due to that undefined element "Id"
Also noticed that the RequestByDotNet.Header.Security.BinarySecurityToken.ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" but RequestByJava (SoapUI) has a different ValueType "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
Another difference, not sure it matters, is that the Request from .net codes has a "mustunderstand" value under the Header.Security set to true while the one from Java does not.
My questions are:
Why is the difference?
How can this be fixed without having to write a Java client?
Some codes used binding and endpoint behavior:
private static CustomBinding BuildCustomBinding()
{
var binding = new CustomBinding();
var textMessageEncoding = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap11
};
var securityBindingElement =
SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
binding.Elements.AddRange(textMessageEncoding, securityBindingElement, new HttpsTransportBindingElement());
return binding;
}
private static void CallAccountService()
{
//credential for test
const string applId = "testuser";
const string pwd = "password";
//for client certificate, import client.pfx to LocalMachine's Trusted Root Certification Authorities and make sure the thumbprint matches
var client = new NOLWSAccountSvc.WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "thumbprintvalue");
//for service certificate, import service-provider.cer to same store location and store name and make sure the thumbprint matches
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindByThumbprint, "thumprintvalue");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
client.Open();
var header = new NOLWSAccountSvc.AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new NOLWSAccountSvc.getActiveAccounts() { applRef = "softact-dev", resetRows = true };
try
{
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
Thanks for your time! Your help will be highly appreciated.
#jdweng Yes, I did; here were two request bodies, first from .Net and 2nd from SoapUI:
.Net Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><h:Authentication u:Id="_2" xmlns:h="http://service.soap.xcompany.com" xmlns="http://service.soap.xcompany.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><application_id>testuserid</application_id><password>testpassword</password></h:Authentication><ActivityId CorrelationId="d7085e6f-b757-46e8-b3eb-319a51d568a3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo8DAzaQVkApDpl1Tc1YTHQwAAAAAMbeMEvBLCUqoD7kEDPHDKYukgggNOf5FtHBB/Sa7ggkACQAA</VsDebuggerCausalityData><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:BinarySecurityToken u:Id="uuid-eb310312-396a-4d00-8922-f77de97138cb-3" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIDYzCCAkugAwIBAgIEaGKzJDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJ1czEPMA0GA1UEChMGU3ByaW50MREwDwYDVQQLEwhQcm9qZWN0czEMMAoGA1UECxMDQk1QMQwwCgYDVQQLEwNUUEExEzARBgNV</o:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>WCpRwVjx89ceVctR8lp9LNGKHeA=</DigestValue></Reference><Reference URI="#_2"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>8/PErh8BL9To5zazpP9CbPFTAa8=</DigestValue></Reference></SignedInfo><SignatureValue>hOtpz7lXvZPPbBD6sV1hxyx3Hc39vj0q2GYKMd8oQbgTbbuKC7QKcZOjktqUxayrzc6h/V0j7Kx3APPONe4F3A2581nK4AQ72yYonsaeXQW0yzSxW/VTsN04uoqCP6IpKXqlAz40VeWGUPJOeGthCKy/9A+NSuqS</SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-eb310312-396a-4d00-8922-f77de97138cb-3"/></o:SecurityTokenReference></KeyInfo></Signature></o:Security></s:Header><s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getActiveAccounts xmlns="http://service.soap.xcompany.com"><applRef>dev</applRef><resetRows>false</resetRows></getActiveAccounts></s:Body></s:Envelope>
SoapUI Request:
(somehow it won't let me past whole xml here.. )
Well, my colleague helped me figure out way to remove the extra headers from the request before it was posted to the Java SOAP service endpoint - the key was to use IClientMessageInspector and implement some logic in the BeforeSendRequest to remove the unwanted headers that were rejected by the service provider; then add a custom FormattingBehavior class to inherit from IEndpointBheavior and in the IEndPointBehavior.ApplyClientBehavior, attach the MyClientMessageInspector; finally add the customer endpoint behavior to the web service client. Here are the codes:
Where and how to remove unwanted request headers:
public class MyClientMessageInspector : IClientMessageInspector
{
public MyClientMessageInspector(ServiceEndpoint endpoint)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Console.WriteLine(request.ToString());
var lstUnwantedStuff = new[]
{
new KeyValuePair<string, string>("Action", "http://www.w3.org/2005/08/addressing"),
new KeyValuePair<string, string>("VsDebuggerCausalityData",
"http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink")
};
foreach (var kv in lstUnwantedStuff)
{
var indexOfUnwantedHeader = request.Headers.FindHeader(kv.Key, kv.Value);
if (indexOfUnwantedHeader>=0)
{
request.Headers.RemoveAt(indexOfUnwantedHeader);
}
}
...
Where and how to use the custom ClientMessageInspector:
internal class MyFaultFormatterBehavior : IEndpointBehavior
{
...
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector(endpoint));
}
}
Where and how to attach custom EndpointBehavior:
private static void CallAccountService()
{
var client = new WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
//Set client certificate
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "xxxxxxxxxx");
//for service certificate
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople,
X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxy");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
//add faultformattingbehavior so we can intercept the fault reply message
client.Endpoint.EndpointBehaviors.Add(new MyFaultFormatterBehavior());
client.Open();
var header = new AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new getActiveAccounts() { applRef = "test", resetRows = true };
try
{
//MyClientMessageInspector.BeforeSendRequest is entered when this called is made
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
What else?
In the proxy classes, need to set the Authentication ProtectionLevel to None while on the Service level it needs to be set as ProtectionLevel.Sign:
Request level:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class getActiveAccountsRequest
{
[System.ServiceModel.MessageHeaderAttribute(Namespace = "http://service.xcompany.com"
, ProtectionLevel = System.Net.Security.ProtectionLevel.None
)]
public AuthenticationHeader Authentication;
Service (Interface) Level:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://service.xcompany.com",
ConfigurationName = "WSAccount"
, ProtectionLevel = ProtectionLevel.Sign
)]
public interface WSAccount
{