axis2 over https starter question - java

I am trying to figure out how to use axis2 over https.
The axis2 guide says:
CommonsHTTPTransportSender can be also
used to communicate over https.
also:
Please note that by default HTTPS
works only when the server does not
expect to authenticate the clients
(1-way SSL only) and where the server
has the clients' public keys in its
trust store. If you want to perform
SSL client authentication (2-way SSL),
you may use the
Protocol.registerProtocol feature of
HttpClient.
So my question is are there are 2 approaches for HTTPS for axis?
1) To use CommonsHTTPTransportSender
2) Uncomment the https connector on apache configuration ??
Or only (1) is the standard approach??
Also what is the problem with client authentication? I know that for apache connector I just need to set the clientAuth. This does not work for axis?
Any input is welcome!
Thanks

Reference: http://axis.apache.org/axis2/java/core/docs/servlet-transport.html
For each protocol (HTTP and/or HTTPS), an AxisServletListener instance must be declared in axis2.xml. If only a single protocol is used, no further configuration is required. For example, if only HTTP is used, the following declaration must be present in axis2.xml:
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener"/>
If both HTTP and HTTPS are used, then things become a bit more complicated. The reason is that in order to expose WSDLs with correct endpoint URIs, AxisServlet must know the ports used by HTTP and HTTPS. Unfortunately the servlet API doesn't allow a Web application to discover all configured protocols. It only provides information about the protocol, host name and port for the current request. If only a single AxisServletListener is configured, then this information is enough to let AxisServlet auto-detect the port number. If both HTTP and HTTPS are used (or if WSDLs are retrieved through transports other than AxisServlet), then AxisServlet has no way of knowing the port numbers until it has processed at least one request for each protocol. To make WSDL generation predictable in this scenario, it is necessary to explicitly configure the port numbers in axis2.xml, such as in the following example:
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8080</parameter>
</transportReceiver>
<transportReceiver name="https" class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8443</parameter>
</transportReceiver>

Here's what I am using in my axis.xml configuration for the https connector approach (Axis 1.4.1).
<transportReceiver name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener">
<parameter name="port" locked="false">9002</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>.keystore</Location>
<Type>JKS</Type>
<Password>changeme</Password>
<KeyPassword>changeme2</KeyPassword>
</KeyStore>
</parameter>
</transportReceiver>
I dumped my keystore under axis2-1.4.1/lib to avoid adding a dedicated classpath.

Related

Cannot stop Spring redirecting https to http

I'm developing project on a Spring Security and everything was going fine until I loaded my project to a production server. I have only http on my local machine but there is https on a production server.
And I faced an error (in case of login error):
Mixed Content: The page at 'https://my.production.com/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://my.production.com/api/login?error=bad-credentials'. This request has been blocked; the content must be served over HTTPS.
and (in case of success login):
Mixed Content: The page at 'https://my.production.com/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://my.production.com/authorities'. This request has been blocked; the content must be served over HTTPS.
I asked my vendor about this issue but they say that "There is no https between you app and nginx, so this is your app problem"...
I tried this, but this solution looks very weird and doesn't solve problem (It requires adding a lot of configuration classes and I guess it shouldn't be so hard). Actually I'm very confused how can this happen, why isn't it the default behavior to redirect to the schema that the request was made...
Also I tried adding this to my Spring Security config:
.and().requiresChannel().anyRequest().requiresSecure()
but this only causes ERR_TOO_MANY_REDIRECTS on my local machine and on a production server...
This didn't help too:
http.portMapper()
.http(8080).mapsTo(8443);
I'm not using Spring boot, but also tried this, no help.
Success authentication configuration looks like this:
SavedRequestAwareAuthenticationSuccessHandler successHandler = new
SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setDefaultTargetUrl(env.getProperty("app.authenticationSuccessUrl"));
When Apache Tomcat is running behind a HTTPS (reverse) proxy, there may be some configuration required for links and redirects to work properly.
Open conf/server.xml, find the Connector element, add the following attributes if not already present:
proxyName - set to your domain name.
proxyPort - set it to 443 if you are using the standard https port.
scheme - set to "https" if site is accessed with https.
secure - set to "true" for https.
<Connector proxyName="my.production.com" proxyPort="443" scheme="https" secure="true" ...>
Reference: Apache Tomcat 7: The HTTP Connector

Require HTTPS with Spring Security behind a reverse proxy

I have a Spring MVC application secured with Spring Security. The majority of the application uses simple HTTP to save resources, but a small part processes more confidential information and requires an HTTPS channel.
Extract from the security-config.xml :
<sec:http authentication-manager-ref="authenticationManager" ... >
...
<sec:intercept-url pattern="/sec/**" requires-channel="https"/>
<sec:intercept-url pattern="/**" requires-channel="http"/>
</sec:http>
All worked fine until we decided to migrate it to the main server, where the application servers run behind reverse proxies. And as now HTTPS is processed by the reverse proxies the application server only sees HTTP requests, and disallows access to the /sec/** hierarchy.
After some research, I found that the proxies add a X-Forwarded-Proto: https header (*), but in Spring Security HttpServletRequest.isSecure() is used to determine the channel security offered (extract from SecureChannelProcessor javadoc).
How can I tell Spring Security that a X-Forwarded-Proto: https header is enough for a secure request?
I know I could report that part on proxies configuration, but the proxies administrator really does not like that solution, because there are many application behind the proxies and the configuration could grow to a non manageable state.
I an currently using Spring Security 3.2 with XML config, but I'm ready to accept answers based on Java config and/or more recent version.
(*) Of course, the proxies remove the header if it was present in incoming request, so the application can be confident in it.
Kind of a followup to NeilMcGuigan's answer that showed that the solution was servlet container side.
Tomcat is even better. There is a valve dedicated to masking the side effects of a reverse proxy. Extract from Tomcat documentation for Remote IP Valve:
Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").
Example of the valve configuration :
<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="192\.168\.0\.10|192\.168\.0\.11"
remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by"
protocolHeader="x-forwarded-proto" />
That way with no other configuration of the application itself, the call to Request.isSecure() will return true if the request contains a header field of X-Forwarded-Proto=https.
I had thought of two other possibilities, but definitively prefere that one :
use a filter active before Spring Security ChannelProcessingFilter to wrap the request with a HttpServletRequestWrapper overriding isSecure() to process a X-Forwarded-Proto header - need writing and testing the filter and the wrapper
use a Spring BeanPostProcessor to look for a ChannelProcessingFilter and manually inject a ChannelDecisionManager able to consider the X-Forwarded-Proto header - really too low level
Spring Boot makes it dead simple (at least with embedded Tomcat).
1. Add the following lines to your application.properties:
server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
2. Do the following trick with your HttpSecurity configuration.
// final HttpSecurity http = ...
// Probably it will be in your `WebSecurityConfigurerAdapter.configure()`
http.requiresChannel()
.anyRequest().requiresSecure()
Source is Spring Boot reference guide
84.3 Enable HTTPS When Running behind a Proxy Server
Please also check the answer below for a specifics related to Spring Boot 2.2
If your site is HTTPS and you're running Apache Tomcat behind another system that's handling TLS termination, you can tell Tomcat to "pretend" that it's handling the TLS termination.
This makes request.isSecure() return true;
To do so, you need to add secure="true" to your Connector config in server.xml.
https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
See also the scheme attribute.

CAS 4.x & Spring Security without SSL

is it possible to use the CAS 4.x Server with Spring Security without SSL?
I already tried to edit the CAS Server settings.
I added
<bean id="ticketGrantingTicketCookieGenerator"
class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="TGC"
p:cookiePath="/cas" />
to the ticketGrantingTicketCookieGenerator.xml
and I also added
<bean id="warnCookieGenerator"
class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="CASPRIVACY"
p:cookiePath="/cas" />
to the warnCookieGenerator.xml
I still get the following error from CAS:
Authentication failed because url was not secure.
Is there any other configuration which can make CAS without SSL possible or isn't it possible the current version?
Thanks in advance...
CAS Server were made to be a secure channel to do authentication. So the CAS Server does not work with HTTP. You can change the source of CAS to do it for you, but this does make sense for me.
<bean id="proxyAuthenticationHandler"
class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" p:requireSecure="false"/>

Preemptive authentication method in Apache Axis?

I sort of understand that I'm using Apache Axis 1.4 for querying a web service.
I was given a WSDL file, and that generated a XXXXImplServiceLocator class that extends org.apache.axis.client.Service and implements a generated interface that extends javax.xml.rpc.Service.
My "bussiness code" calls the getXXXXImplPort(URL) method on a new XXXXImplServiceLocator instance, and then calls:
((Stub) port).setTimeout(timeout);
((Stub) port).setUsername(username);
((Stub) port).setPassword(password);
Stub is org.apache.axis.client.Stub.
After setting those parameters, I simply call some getYYY() method, that represents the query to one of the services exposed by the remote service and gives me back a "domain" object with the results.
The problem is that I have to use preemptive authentication with this service. I've tried querying via soapUI, and I won't have any result unless I set the preemptive authentication mode.
I've tried googling how to set that mode, but found nothing. All they say about is Preemptive authentication with Apache HttpClient, that can be very well "embedded" or used by Axis, but I really didn't see how to mix this.
The only code I have that interacts with this ServiceLocator is the initial setup, and then just queries.
How can I set that preemptive authentication mode? Am I missing something? What am I not understanding so that I can't solve this issue?
Smells like a pretty trivial problem, but maybe the fact I don't understand this very well prevents me from solving the issue.
Thanks in advance, yeah :)
To force Apache Axis to use pre-emptive authentication, set the username and password like so:
import org.apache.axis.client.Call;
import org.apache.axis.client.Stub;
....
....
((Stub) client)._setProperty(Call.USERNAME_PROPERTY, "username");
((Stub) client)._setProperty(Call.PASSWORD_PROPERTY, "password");
That said, if you still want to use the Apache HttpClient as the transport, you can do so by setting the following in Axis client configuration file which in my case is client_config.wsdd:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
.....
.....
<!-- use CommonsHTTPSender instead of the default HTTPSender -->
<!-- <transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender" /> -->
<transport name="http" pivot="java:org.apache.axis.transport.http.CommonsHTTPSender" />
.....
.....
</deployment>
I got the above from here.
You can use the Apache Rampart module to implement WS Security. It plugs in at the service level and will handle all things WS-Security like username/token, X.509 auth, etc.
Its not trivial, but its not that difficult either. We did it here to get an Axis server talking to an Oracle SOA server using WSS.

How to get WCF and Java clients to work. Expert help needed

Background (a wee bit long):
A few years back I wrote for a customer a WCF service that is configured to use the basicHttpBinding with security mode = "Transport" with clientCredentialType = "Certificate", i.e. the clients are authenticating themselves using a (client) certificate. The service employs a custom AuthorizationManager that checks if the thumbprint of the incoming certificate is present in a predefined list of valid certificate thumbprints. If the incoming certificate is deemed valid, the operation is allowed to continue (if not, an exception is thrown).
The service has worked flawlessly for approximately four years and everyone's been happy. However, as so often happens requirements change and recently my customer has been approached by developers wishing to connect their applications to my customer's service. The only problem is that these developers are using some variant of Java as their preferred platform and now we are facing some serious problems. To make a long story short, no one has managed to get their Java implementation (e.g. Metro, Axis2) to work with the service as it is presently configured.
Last week we tried getting it to work with a client written in Java (Metro, JAX-WS) by changing the binding to the wsHttpBinding with security mode = "TransportWithMessageCredential" with Message clientCeredentialType = "UserName". I also added a custom UserNamePassWordValidatorType to the service credentials element in the config file.
I then commented out the custom AuthorizationManager since no certificate was coming from the client.
Lo' and behold, this time we got both SoapUI and the Java client proper to talk to the service.
(Btw, our service is self-hosted in a Windows Service)
Happy as can be, we decided to configure the service with two bindings, the existing basicHttpBinding that's been working without a glitch for a long time, and the newly tested wsHttpBinding. So we would have something like:
<services>
<service name="SuperDuperService" behaviorConfiguration="superDuperBehaviour">
<endpoint binding="basicHttpBinding" contract="ISuperDuperService" bindingConfiguration="SecureTransport"/>
<endpoint binding="wsHttpBinding" address="stws" contract="ISuperDuperService" bindingConfiguration="SecureTransportAndSoap"/>
<endpoint binding="mexHttpsBinding" address="mex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://<url + port>/SuperDuperService"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="SecureTransport" maxBufferSize="2065536" maxBufferPoolSize="524288" maxReceivedMessageSize="2065536">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
<readerQuotas maxDepth="32" maxStringContentLength="6553600" maxArrayLength="2065536"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="SecureTransportAndSoap">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="superDuperBehaviour">
<serviceCredentials>
<!-- The following element specifies the certificate use by this service for HTTPS (SSL) based transport security -->
<serviceCertificate findValue="<some identifier>"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode ="Custom" customUserNamePasswordValidatorType
="SupportClasses.CustomUserNameValidator,SupportClasses"/>
</serviceCredentials>
<!-- The following element specifies how we're authorizing based on the client certificates received -->
<serviceAuthorization serviceAuthorizationManagerType="SupportClasses.AuthorizationManager, SupportClasses"/>
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
So where is the problem you may ask? Well, see that <serviceBehavior> element? As you well may know this element applies globally to the service meaning that during run-time both the CustomUserNameValidator and the AuthorizationManager will be called. The latter will complain that there is no certificate present when a client calls the service using the wsHttpBinding!
Argh!
Alternative solutions.
So far, these are the alternative solutions I have come up with:
Alternative 1) Create another Windows Service hosting our WCF service on a different URL. Then both services will have a separate configuration.
Alternative 2) Create two service implementations hosted in the same Windows Service and expose them both in the element each with their own binding and serviceBehaviour
Alternative 3) Figure out if it is at all possible to keep the current configuration and have the CustomUserNameValidator and the AuthorizationManager coexist peacefully
Sorry for this long post, but I needed to be thorough when providing the background for my question(s).
Question 1) Has anyone gotten WCF to work with Java clients using nontrivial configurations?
Question 2) Has anyone got a suggestion on how to solve alternative 3? (if at all possible)
Question 3) Which one, if any, of the above alternatives, would you recommend?
Question 4) Is there other alternatives you know of that I haven't thought of?
For the record, I've looked into the WCF interoperability tool, but I can't really see how it can help us. If anyone reading this has had good results using the interoperability "wizard",
please let me know.
Thanks in advance.
--norgie
I would start by adding a second element in //services and configure that with a new #bindingConfiguration attribute and a distinct #address attribute. I think that will be simpler that alternatives 1, 2, or 3; or maybe it is alternative 3, I can't tell.
Web services exist to provide interoperation that is language-, vendor-, platform-, and vendor-neutral. WCF and Java interoperate in real world solutions every day.
Have you looked at this series on WCF and Java interoperation?
Also, it sounds like you would benefit from using some diagnostics tools that will let you see the different between the .NET/WCF client message and Java client messages. Use Fiddler or some other sniffer utility to see the messages on the wire. Turn on WCF tracing to see what WCF does once it receives the message.

Categories

Resources