I am new to the Authorized.net API and facing the below E00007, User authentication failed due to invalid authentication values. in authorized.net. I am using the authorize.net version to call the GetTransactionDetails API.
Any idea on what is the issue ? Any help ?
<dependency>
<groupId>net.authorize</groupId>
<artifactId>anet-java-sdk</artifactId>
<version>1.8.6</version>
</dependency>
and I am using the below code
public class GetTransactionDetails {
public static final String apiLoginId= "6LaBc8HJ6Q";
public static final String transactionKey= "XXXXXXXX";
public static void main(String[] args) {
ApiOperationBase.setEnvironment(Environment.SANDBOX);
MerchantAuthenticationType merchantAuthenticationType = new MerchantAuthenticationType() ;
merchantAuthenticationType.setName(apiLoginId);
merchantAuthenticationType.setTransactionKey("transactionKey");
ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);
//need valid transacaction Id to run
String transId = "60024624183";
GetTransactionDetailsRequest getRequest = new GetTransactionDetailsRequest();
getRequest.setMerchantAuthentication(merchantAuthenticationType);
getRequest.setTransId(transId);
GetTransactionDetailsController controller = new GetTransactionDetailsController(getRequest);
controller.execute();
GetTransactionDetailsResponse getResponse = controller.getApiResponse();
TransactionDetailsType transactionDetailsType = getResponse.getTransaction();
if (getResponse!=null) {
if (getResponse.getMessages().getResultCode() == MessageTypeEnum.OK) {
System.out.println(getResponse.getMessages().getMessage().get(0).getCode());
System.out.println(getResponse.getMessages().getMessage().get(0).getText());
System.out.println("---------------------------------------");
System.out.println("Auth Amount : "+transactionDetailsType.getAuthAmount());
System.out.println("Auth Code : "+transactionDetailsType.getAuthCode());
System.out.println("Response Reason Description : "+transactionDetailsType.getResponseReasonDescription());
System.out.println("Transaction Status : "+transactionDetailsType.getTransactionStatus());
System.out.println("Submit Date : "+transactionDetailsType.getSubmitTimeLocal());
}else{
System.out.println("Failed to get transaction details: " + getResponse.getMessages().getResultCode());
List<Message> messages = getResponse.getMessages().getMessage();
for (Message message : messages) {
System.out.println("Code : "+message.getCode());
System.out.println("Text : "+message.getText());
}
}
}
}
}
output:
06/02/17 00:35:48,733: INFO [pool-1-thread-1] (net.authorize.util.LogHelper:24) - Use Proxy: 'false'
Failed to get transaction details: ERROR
Code : E00007
Text : User authentication failed due to invalid authentication values.
Can you try removing the quotes from setTransactionKey
merchantAuthenticationType.setTransactionKey("transactionKey");
change to
merchantAuthenticationType.setTransactionKey(transactionKey);
There are multiple causes of this error, which may include:
Using the wrong API Login ID (the "name" field in some of the API calls)
Using the wrong Transaction Key
Using the wrong API endpoint. Authorize.net has two API endpoints, one for sandbox and one for production:
Sandbox API Endpoint: https://apitest.authorize.net/xml/v1/request.api
Production API Endpoint: https://api.authorize.net/xml/v1/request.api
To test your Authorize.net authentication credentials, go to [Authorize.net's API documentation site] and choose API Endpoints and Authentication, then the test your authentication credentials box.1
Related
I have the following situation. I have implemented in a Spring Boot application a user management system using keycloak.
Its working perfectly fine on my test systems. Only in Production I always get an 404 error when trying to create a keylcoak user.
com.example.solar.frontend.usecase.exceptions.KeycloakException: Error creating Keycloak user. Get Response 404
Sep 14 08:34:08 solar[23098]: at com.example.solar.frontend.adapter.outgoing.KeycloakUserService.createUser(KeycloakUserService.java:59) ~[classes!/:0.0.4]
This is my service:
public class KeycloakUserService implements UserService {
private final RealmResource realmResource;
#Autowired
public KeycloakUserService(KeycloakProvider keycloakProvider, #Value("${keycloak.realm}") String realm) {
realmResource = keycloakProvider.keycloak().realm(realm);
}
public String createUser(KeycloakUserRequest userRequest) throws KeycloakException {
UsersResource usersResource = realmResource.users();
CredentialRepresentation credentialRepresentation = createPasswordCredentials(userRequest.getPassword());
UserRepresentation kcUser = new UserRepresentation();
kcUser.setUsername(userRequest.getUsername());
kcUser.setCredentials(Collections.singletonList(credentialRepresentation));
kcUser.setFirstName(userRequest.getFirstname());
kcUser.setLastName(userRequest.getLastname());
kcUser.setEmail(userRequest.getEmail());
kcUser.setEnabled(true);
kcUser.setEmailVerified(false);
Response response = usersResource.create(kcUser);
if (response.getStatus() == HttpStatus.SC_CREATED) {
String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
log.info("Successfully created user in Keycloak userId: {}, email: {}, firstname: {}, lastname: {}", userId,
kcUser.getEmail(), kcUser.getFirstName(), kcUser.getLastName());
return userId;
} else {
throw new KeycloakException("Error creating Keycloak user. Get Response " + response.getStatus() + " " + response.getStatusInfo().getReasonPhrase());
}
}
This is my configuration in application.properties:
keycloak.realm=<realm>
keycloak.auth-server-url=http://<loadbalancer-keycloak-url>/auth/
keycloak.resource=solar
keycloak.credentials.secret=<secret>
This config is working on dev perfectly, but there I calling keycloak auth url directly instead over a loadbalancer. (http protocol is correct). Calling the url via browser, the keycloak admin index page is returned, so url is correct.
Any idea, which config I am missing, or what else I can do?
Finally I could solve the issue. It was a firewall issue.
best regards
Michael
Need help to implement login via Vkontakte OAuth.
According to spring-boot docs made this:
#Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(vkClientRegistration());
}
private ClientRegistration vkClientRegistration() {
return ClientRegistration.withRegistrationId("vk")
.authorizationUri("https://oauth.vk.com/authorize")
.clientId("######")
.clientSecret("######")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("friends", "groups")
.tokenUri("https://oauth.vk.com/access_token")
// .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
// .userNameAttributeName(IdTokenClaimNames.SUB)
// .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Vkontakte")
.build();
}
As a result: context starts, localhost:8080 redirects to authorization page.
But after clicking "Allow" button browser comes back to login page with error:
[invalid_token_response] An error occurred while attempting to
retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized: [no
body]
I used VK API documentation from this:
https://dev.vk.com/api/access-token/authcode-flow-user
What should I correct to complete authorization flow?
Update
Debugging I found the reason of such behavior:
VK service returns access token like this:
{
"access_token":"ed0f46118dec0a5e6935ca198......",
"expires_in":86400,
"user_id":1111111,
"email":"1111222#mail.ru"
}
And it does not have property "token_type". As a result OAuth2AccessToken constructor fails.
public OAuth2AccessToken(TokenType tokenType, String tokenValue, Instant issuedAt, Instant expiresAt,
Set<String> scopes) {
super(tokenValue, issuedAt, expiresAt);
Assert.notNull(tokenType, "tokenType cannot be null");
this.tokenType = tokenType;
this.scopes = Collections.unmodifiableSet((scopes != null) ? scopes : Collections.emptySet());
}
There is a solution which detailed describes configuring flow at the link (in Russian)
I am trying to upgrade an application (it should fetch emails from a mailbox every few minutes) from Microsoft EWS deprecated API to the new Graph API, but I am facing some issues.
This is my class for the connector :
public class O365graphApiConnector {
private final GraphServiceClient<Request> graphClient;
public O365graphApiConnector(String clientId, String username, String password) {
final UsernamePasswordCredential usernamePasswordCredential =
new UsernamePasswordCredentialBuilder()
.clientId(clientId)
.username(username)
.password(password)
.build();
final TokenCredentialAuthProvider tokenCredentialAuthProvider =
new TokenCredentialAuthProvider(usernamePasswordCredential);
graphClient=GraphServiceClient.builder()
.authenticationProvider(tokenCredentialAuthProvider)
.buildClient();
}
public User getUserProfile() {
return graphClient.me().buildRequest().get();
}
public MessageCollectionPage getOutlookEmails() {
return graphClient.me().messages().buildRequest().get();
}
}
I am using com.azure:azure-identity:1.4.2 and com.microsoft.graph:microsoft-graph:5.8.0.
I build the connector, passing the clientId, username and password. I am able to call getUserProfile , and I am getting something, so the authentication "works".
However, I get a 404 when calling getOutlookEmails :
SEVERE: Throwable detail:
com.microsoft.graph.http.GraphServiceException: Error code:
ResourceNotFound Error message: Resource could not be discovered.
GET https://graph.microsoft.com/v1.0/me/messages SdkVersion :
graph-java/v5.8.0
404 : Not Found [...]
When I run this in debug mode and intercept the token, it seems to be OK though : I have a bunch of rights that my admin has given to the applicative account :
"scp": "EWS.AccessAsUser.All Mail.Read Mail.Read.Shared Mail.ReadBasic Mail.ReadWrite
Mail.ReadWrite.Shared Mail.Send Mail.Send.Shared MailboxSettings.ReadWrite User.Read User.Read.All User.ReadWrite profile openid email"
This is part of what we see on the admin side (more rights were added after the screenshot was taken) :
My understanding is that this should be enough to get access to the emails of the given mailbox programmatically, but apparently, it's not.
Any idea of what I am missing ?
actually, the technical "user" I am using didn't really have a mailbox (despite the user name being an email address.. that confused me).
It had been given the permissions on the given mailbox I am interested in though, so the fix is simply to select the mailbox/user before retrieving the messages :
public MessageCollectionPage getOutlookEmailsFor(String mailbox) {
return graphClient.users(mailbox).messages().buildRequest().get();
}
I want to insert (index) some data into Elastic Search running in Elastic Cloud in a Java application.
To do so, I wrote the following piece of code:
void sendStuffToElasticSearch() {
RestHighLevelClient client = null;
try {
client = new RestHighLevelClient(
RestClient.builder(CLOUD_ID)
);
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.addHeader("Authorization", String.format("ApiKey %s",
API_KEY));
final RequestOptions requestOptions = builder.build();
IndexRequest request = new IndexRequest("posts");
request.id("1");
String jsonString = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
request.source(jsonString, XContentType.JSON);
IndexResponse indexResponse = client.index(request, requestOptions);
System.out.println("indexResponse");
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(client);
}
}
API_KEY is the key I generated according to this tutorial which also says I need to send it in the Authorization header in the following format: Authorization: ApiKey $EC_API_KEY.
When I run the above code, I am getting the following error:
org.elasticsearch.client.ResponseException: method [PUT], host [https://XXXXXXXXXX:9243], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 401 Unauthorized]
{"error":{"root_cause":[{"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}}],"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}},"status":401}
at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
... 30 more
How can fix this, i. e. provide all authentication-related data in the way Elastic Cloud expects them?
I am using following libraries:
<properties>
[...]
<elastic-search-client.version>7.11.1</elastic-search-client.version>
</properties>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
Update 1: Base64-encoding of the API key as suggested here (see code below) did not help.
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.addHeader("Authorization", String.format("ApiKey %s",
Base64.getEncoder().encodeToString(API_KEY.getBytes(StandardCharsets.UTF_8))));
final RequestOptions requestOptions = builder.build();
Update 2: Changing the way I create the client, did not help, either (see below).
Header[] defaultHeaders =
new Header[]{new BasicHeader("Authorization",
String.format("ApiKey %s",API_KEY))};
final RestClientBuilder builder1 = RestClient.builder(CLOUD_ID);
builder1.setDefaultHeaders(defaultHeaders);
client = new RestHighLevelClient(
builder1
);
Update 3: I changed the supplied API key to
public static final String BASE64_API_KEY = Base64.getEncoder().encodeToString(String.format("%s:%s", ID, KEY).getBytes());
as suggested by Ricardo Ferreira.
Now I am getting a different error:
org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}
at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
... 30 more
Update 4:
After I created the index in question, the error message changed to this:
org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/camunda-1/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}
It's not working because you are using the wrong API Key.
But don't worry: these things happen a lot. It certainly happened to me.
The API Key that you are creating is for you to issue REST requests against Elasticsearch Service — which is the entity that governs your Elasticsearch and Kibana clusters.
To make it work, you need to create an API Key from Elasticsearch specifically. To create one, go to the Dev Tools Console and issue the following request:
POST _security/api_key
{
"name": "my-api-key",
"expiration": "7d",
"role_descriptors": {
"custom-role": {
"cluster": ["all"],
"index": [
{
"names": [
"index-1",
"index-2"
],
"privileges": ["all"]
}
]
}
}
}
If executed successfully, you will get a response like this:
{
"id" : "liKs_XcBrNsSAgwboCN9",
"name" : "my-api-key",
"expiration" : 1615473484899,
"api_key" : "NC3ZeIb_SGWjGJRZVoOf2g"
}
Take note of the fields id and api_key. You are going to need them to create the authorization header:
String apiKey = String.format("%s:%s", id, api_key);
apiKey = Base64.getEncoder().encodeToString(apiKey.getBytes());
String authorization = String.format("ApiKey %s", apiKey);
After this just use the authorization in your Java code:
builder.addHeader("Authorization", authorization);
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
{