How to extend expiration time of SOAP header message timestamp - java

Is there a way to prolong time to live(expiration time) of a SOAP message header timestamp to prevent
"WSSecurityException: The message has expired" exception. The default is set to 300 seconds(5 minutes). We would like to extend it to 10 minutes.
We have a java ee(jdk 1.8.0_77) service that uses SOAP messages to communicate with android client.
It runs on Jboss Wildfly 10.0.0. server, and uses Apache CXF(version 3.1.4) WS security to handle messages. wss4j security policy is version 2.1.4
We have wsdl file, Custom WS-Security Endpoint (server-endpoint-config.xml file), and our Schema.xsd file. I don't know what parts of those files are relevant, so I'll provide them if someone needs more info.
I've tried using a custom interceptor that extends WSS4JInInterceptor, but that part of code never gets executed.
#WebService
(
portName = "HelloPort",
serviceName = "BampayService",
wsdlLocation = "WEB-INF/BampayService.wsdl",
targetNamespace = "http://bampay.bamcard.ba/",
endpointInterface = "ba.bamcard.bampay.Hello"
)
#EndpointConfig
(
configFile = "WEB-INF/server-endpoint-config.xml",
configName = "Custom WS-Security Endpoint"
)
#InInterceptors(// I added this part
interceptors = {"ba.bamcard.helpers.MyInterceptor"}
)
and the code of MyInterceptor
public class MyInterceptor extends WSS4JInInterceptor {
#Override
public int decodeTimeToLive(RequestData reqData, boolean timestamp) {
// return super.decodeTimeToLive(reqData, timestamp);
return 600;
}
}
If needed, I will gladly provide any additional information.
If anyone can help me, I would be very grateful.

Add this property to your server-side security settings to the value you want.
ws-security.timestamp.timeToLive
If you think you are seeing clock-skew between the client(s) and the server as part of the reason for the errors, you'll also want to account for clients that send messages with timestamps in the future.
ws-security.timestamp.futureTimeToLive
ref: https://cxf.apache.org/docs/ws-securitypolicy.html

Related

apache cxf LoggingFeature mask senstive information

I'm using Logging feature to log in/out message to my cxf rest server on Spring boot. Similarly using the same to log outward Rest API connections initiated by cxf WebClient.
I came across few parameters which I do not want to be logged in to the log file. either completely removing them or masking them is sufficient for my case.
I found on the internet that previous (now depreciated) LoginIntercepter had transform operation to modify the log entry. I was not able to find a solution to mask/truncate the log entries wirg LoggingFeature.
any help would be appreciated
Current configuration of the server's logging feature is like below.
factory.setProviders(providers);
LoggingFeature loggingFeature = new LoggingFeature();
loggingFeature.setPrettyLogging(true);
loggingFeature.setLogBinary(false);
loggingFeature.setLogMultipart(false);
factory.getFeatures().add(loggingFeature);
Server server = factory.create();
web client configuration is as below
LoggingFeature loggingFeature = new LoggingFeature();
loggingFeature.setPrettyLogging(true);
WebClient client = WebClient.create(url, Collections.singletonList(new JacksonJsonProvider()),
Arrays.asList(loggingFeature), null);
To change the log message, you can ...
Write a custom LogSender and set it on the LoggingFeature to do custom
logging. All meta data can be access[ed] from the class LogEvent.
(Source: http://cxf.apache.org/docs/message-logging.html)
With a sender like:
// ...
import org.apache.cxf.ext.logging.event.LogEvent;
class MyLogEventSender implements org.apache.cxf.ext.logging.event.LogEventSender {
#Override
public void send(LogEvent event) {
event.setPayload(maskSensibleParameters(event.getPayload()));
}
private String maskSensibleParameters(String pIn) {
// here goes the tricky part
// ... but no details on this in your question
// ... here you can stick to "old" LogInterceptor examples
// ... and also to PrettyLoggingFilter.
}
}
A code example is given by (the default) PrettyLoggingFilter.
To mask (hide) it (completely) is easier and guaranteed more performant, it depends on the used "logging framework" (java.util, log4j or slf4j) and accomplished with an according "logger configuration". (see here)

Spring Remoting with AMQP - Client is not seeing the beans exposed from Server

I'm trying to run example from http://www.baeldung.com/spring-remoting-amqp, even when I set up the connection to the dedicated vhost to my RabbitMQ broker, I can only send the request from client (I see it in RabbitMQ UI), but I never get the answer from the server.
The server seems to bean the service (the returning Impl class) with getBeanDefinitionNames(), but I definitly do not see those beans on the client side. I use annotations to set up beans, not the .xml file.
So the question is - why my client is not seeing the Server beans, I discover it more a less in following way:
#Autowired
private ApplicationContext appContext;
public GetResponse get(String id) {
Service service = appContext.getBean(Service.class);
System.out.println(service.ping());
return new GetResponse();
}
The answer which I get on the level of webservice is:
{
"timestamp": "2018-02-01T10:09:00.809Z",
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.remoting.RemoteProxyFailureException",
"message": "No reply received from 'toString' with arguments '[]' - perhaps a timeout in the template?",
"path": "/v3/app/r"
}
Service:
public interface Service extends Serializable{
String ping();
}
Service Impl:
public class ServiceImpl implements Service {
#Override
public String ping() {
System.out.println("ponged");
return "pong";
}
#Override
public String toString() {
return "to string";
}
EDITED + BOUNTY
In the link you can find extracted modules which I want to connect together. I suppose that it is still about 'not seeing' the beans from one module in the second one.
The action can be trigerd with GET http://localhost:8081/v3/app/u The RabbitMQ settings has to be adjusted to your set-up.
https://bitbucket.org/herbatnic/springremotingexample/overview
I think you shouldn't set the routing key in your client, in amqpFactoryBean (and the one you set seems invalid):
https://bitbucket.org/herbatnic/springremotingexample/src/b1f08a5398889525a0b1a439b9bb4943f345ffd1/Mod1/src/main/java/simpleremoting/mod1/messaging/Caller.java?at=master&fileviewer=file-view-default
Did you try to run their example?
https://github.com/eugenp/tutorials/tree/master/spring-remoting/remoting-amqp
Just stumbled upon this question 3 years later.. trying to run the Baeldung example!
I tried debugging the issue and as far as I can tell, something internal in the AMQP implementation of spring remoting is not using the correct Routing Key when sending the client message, meaning the payload arrives at the broker and is never put into the queue for processing, we then timeout after 5s (default) on the client.
I tried the other answer by Syl to remove the routingKey however it doesn't seem to allow us to create a binding without one, and even when creating a binding directly on the broker management page (without a routing key) it doesn't route the messages.
I have not managed to make the example work, however I found a blog post on fatalerrors.org that shows a custom implementation of the AmqpProxyFactoryBean and it has custom handling for the routing key, this one works.
I've create this gist with the example that is working for me in case the blog post above goes under.
One other thing to note is that on the Baeldung example they are using a DirectExchange, while here we are using a TopicExchange.

How to use ws-security info per sending soap message in CXF?

I like to be able to dynamically change/set the ws-security info per sending soap message in cxf. How can this best be done.
Details: I want to change settings like keystore name, keystore alias, password, host name, etc.. during runtime, preferable per sending message.
Currently I am using: jaxws client with WSS4JOutInterceptor and WSS4JInInterceptor interceptor for signing. And I am using http conduit with tls client parameters for SSL/TLS communications.
Both the jaxws client and http conduit are configured in spring and have their configuration like keystore name, alias and password set in the Spring config.
I see options:
1) I change these settings during runtime through a global property.
2) I change these settings per sending message (preferable).
2) Is preferable but most difficult I think.
How should I do this?
I was thinking about:
a) jaxws client: make my own in- and out interceptor that intercepts a message and use the correct (cached) WSS4JOutInterceptor interceptor depending on the security settings that that message requires. If the WSS4JOutInterceptor interceptor doesn't exists in cache, it's created (I probably have max 5 WSS4JOutInterceptor instances cached).
However, how can I determine which settings are required in my interceptor as that is known in an other part of the app when talking to the #Webservice proxy to create and send the soap request/message...
Maybe I could be able to add some kind of securityInfo object to the soap message through the JaxWsClientProxy, but how ?...
Or maybe I can set the interceptors when sending/creating the soap message when this security info is still know. This will then be a light weight interceptor containing the required settings, linking to the cached interceptors, that is selected depending on the settings...
b) http conduit: using a ConduitSelector (never used it but will find out), such that I am able to select the correct http conduit, but I have the same problem as in (a): "How to determine which settings I should use" as they are known when creating/sending a soap message and the interceptors are set later...
Probably I have to set an conduit selector per sending message..
At the end the above become a big story ;), but I hope it's clear you have can give some advice?
I have found the org.apache.cxf packages to be very helpful in keeping me from having to write custom classes and have been able to stick to the basic interface.
For your instance, the approach might look like:
use a JAX-WS or wsimport client
use the cxf WSS4JOutInterceptor with dynamic properties
use a dynamic CallbackHandler class for access to the keystore
A typical (wsimport'd) client public API might look like:
public class SomeServiceClient
{
public SomeService getSomeService( URL url )
{
SomeService_Service svc = new SomeService_Service();
SomeService someService = svc.getSomeServicePort();
Client client = ClientProxy.getClient( someService );
Endpoint cxfEP = client.getEndpoint();
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put( WSHandlerConstants.ACTION, "Signature" );
outProps.put( WSHandlerConstants.USER, "foo" );
outProps.put( WSHandlerConstants.PW_CALLBACK_CLASS, SomeClientCallbackHandler.class.getName() );
outProps.put( WSHandlerConstants.SIG_PROP_FILE, "client-sign.properties" );
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
cxfEP.getOutInterceptors().add( wssOut );
return someService;
}
}
You could provide some logic to determine which WSHandlerConstants.USER value to pass, which PW_CALLBACK_CLASS to use, and which SIG_PROP_FILE to use.
The properties file could look like the following. You could simply have multiple files to choose from, or you could just dynamically add these properties in the class:
# properties for accessing the java keystore using Merlin
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=bar
org.apache.ws.security.crypto.merlin.keystore.alias=foo
org.apache.ws.security.crypto.merlin.keystore.file=foobar.keystore
Finally, your CallbackHandler will need to provide the password for the alias of the cert you identified in the keystore. This could also have some dynamic logic in it.
public class SomeClientCallbackHandler implements CallbackHandler
{
#Override
public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException
{
for( Callback thisCallback : callbacks )
{
WSPasswordCallback pwcb = (WSPasswordCallback)thisCallback;
String user = pwcb.getIdentifier();
int usage = pwcb.getUsage();
if( usage == WSPasswordCallback.SIGNATURE )
{
if( "foo".equals( user ) ) pwcb.setPassword( "bar" );
}
}
}
}
In the end, there is not much more work to make this all 'dynamic' to handle multiple keystores versus the work needed to just do it once. It might be preferable over coding your own 'in' or 'out' interceptors.
The accepted answers to this question appear to be (from http://www.mail-archive.com/users#cxf.apache.org/msg29804.html):
Hi Ed,
As I already wrote, you don't even need the interceptor to change the
properties. You can do it in your client by sending message:
AddNumbers port = (AddNumbers)service.getPort(portName,
AddNumbers.class);
((BindingProvider)port).getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES,
).
Although, If you would like to do it in interceptor, you can pass
necessary information with message properties using the same technic.
The most standard and recommended way to control security in CXF is
using WS-Policy. You also can apply it dynamically at the runtime. If
this way is interesting for you, I can provide further information
how to set WS-Policy dynamically.
Cheers, Andrei.
(from http://www.mail-archive.com/users#cxf.apache.org/msg29809.html):
If you do:
((BindingProvider)port).getRequestContext().put("thread.local.request.context",
"true");
than future calls to getRequestContext() will use a thread local
request context. That allows the request context to be threadsafe.
(Note: the response context is always thread local in CXF).
Details in
http://cxf.apache.org/faq.html#FAQ-AreJAXWSclientproxiesthreadsafe%3F
Cheers, Andrei.

SOAP Header using JAX-WS(Server Side)

The requirement is to include security attributes in header of Soap Message in every WebService request. One way to include is:
#WebService
#SOAPBinding
(
style = javax.jws.soap.SOAPBinding.Style.DOCUMENT,
use = javax.jws.soap.SOAPBinding.Use.LITERAL
)
public interface UserService
{
#WebMethod
public AuthenticateResponse authenticateUser(AuthenticateRequest request, #webParam(header=true) ApplicationCredential appcredential);
#WebMethod
public UserDetailResponse getUserDetail(UserDetailRequest request, #webParam(header=true) ApplicationCredential appcredential);
}
But, with the above mentioned approach, I need to include ApplicationCredential at every operation. It doesn't look good. I am looking for if we can include this ApplicationCredential class in BaseRequest Class and mention there that it is going to be a part of Soap Header(through some annotaion), that would be really helpful. For ex:
public class BaseRequest
{
#SomeAnnotation which states that Appcedential is a part of Soap Header
ApplicationCredential appcredential;
}
So far, I am unable to find any way to do this. Any help would be highly appreciated.
I know it's a while ago you asked that question, and you may have found out yourself already, but I answer to it anyway: Try to avoid to create your own authentication handshake for Web Services - instead use either Web Service message level security if your server and client provide it, or just use transport level security, e.g. Basic Authentication and/or SPNEGO.
The selection of the authentication mechanism depends mainly on your context: If you provide the service within a company network, use whatever is provided there, or Basic Authentication if no central authentication infrastructure is in place. If you provide your Web Service to the Internet, the easiest way to do authentication is again Basic Authentication (via SSL), but that again depends on the kind of service consumers you envision.
This answer creates more questions, I guess, sorry about that. My main point is that you should not try to reinvent the wheel again =:-)

Creating a web-service client with a known but inaccessible wsdl

We have been provided with a wsdl and xsd schema by a company we are working with via email. The web-services we are interfacing with are accessed through a IPsec tunnel. There are local references(on their end) in the published WSDL which means we cannot consume it.
1st question: Is this a common setup? I thought the point of having a WSDL was not only to define the contract but to also expose the service to consumers.
I can easily generate client/server code off of the provided WSDL using wsimport, wsconsume, etc.. I know when my generated client makes a call to my generated service it produces the correct message I need.
2nd Question: Is there an easy way to route this to a different soap address?
I just want to be able to do something like:
SalesTaxService svc = new SalesTaxService();
SalesTax tax = svc.getSalesTaxPort()
tax.getRate("NY");
But not use the soap address defined in the WSDL. I would like to avoid writing a bunch of dispatch clients for each method.
Am I missing something?
*In response to skaffman:
This is what was generated. It defaulted to wsdlLocation as a name shrug
#WebServiceClient(name = "SomeService")
public class SomeService_Service extends Service {
public SomeService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SomeService_Service(URL wsdlLocation) {
super(wsdlLocation, new QName("urn:some_service", "SomeService"));
}
}
I thought the point of having a WSDL
was not only to define the contract
but to also expose the service to
consumers.
No, WSDL is purely a descriptive tool, it has no real runtime role. The web service operates completely independently of the WSDL. It's not uncommon for the WSDL to not be exposed.
Is there an easy way to route this to
a different soap address?
That depends entirely on what web service implementation you're using, and you don't say, although I'm guessing JAX-WS. If that's the case, the artifacts that JAX-WS's tools generate allow you to pass in the URL to the client stub constructors, I think.
So I figured out why I was having a problem. I was assuming that the wsdlLocation had to be the WSDL that the actual service was publishing. This of course is not the case. The solution is to package a local WSDL with the correct SOAP:Address for the actual service into the client.
edit
I found out that you can alter the endpoint address programmatically without having to alter the actual WSDL:
HelloService service = new HelloService (
this.getClass().getResource("originalHello.wsdl"),
new QName("http://example.org/hello", "HelloService "));
HelloPort proxy = service.getHelloPort();
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpointaddress");
proxy.sayHello("Hello World!");
Credit goes to : Jianming Li

Categories

Resources