Apache axis2 and Rampart not preventing 'replay attacks' - axis2

We use one of the older versions of apache axis2 for our web services framework. We are using rampart 1.2 as part of that.
Am trying to use password digest with ‘nonce’ and ‘timestamp’ mechanism for authentication. We’re getting rampart to do the verification.
I’ve got the authentication verification mechanism working fine (inc. password callbacks, etc.)
The issue I’m having concerns getting rampart to recognise a ‘replay attack’, basically the functionality of the rampart module associated with recognising these seems to be inactive.
I can send the same security header to my axis2 service any number of times (even sending a security header I generated yesterday) and it authenticates fine and completes the webservice request.
My best guess is : I’m missing a config setting somewhere for the rampart module that enables the functionality to detect replay attacks.
I’ve tried both the config suggestions given in the links below (in the services.xml file) and neither seem to work :-
http://hasini-gunasinghe.blogspot.com.au/2012_02_01_archive.html
http://axis.apache.org/axis2/c/rampart/docs/configurations.html (right at the bottom, it mentions ‘Replay attacks’)
Anyone able to help or give me some idea what I'm missing and where (I'd imagine it's config setting related) ?
I've got the module declaration for rampart in my axis2.xml file :-
<module ref="rampart"/>
And I have what I believe to be the rampart config settings in my services.xml file after all my operations are declared ;-
<parameter name="InflowSecurity">
<action>
<items>UsernameToken Timestamp</items>
<passwordCallbackClass>com.myCompany.service.dummy.MyAuthenticator</passwordCallbackClass>
</action>
</parameter>
<rampart:rampartconfig xmlns:rampart="http://ws.apache.org/rampart/policy">
<rampart:timestampprecisioninmilliseconds>true
</rampart:timestampprecisioninmilliseconds>
<rampart:timestampttl>300</rampart:timestampttl>
<rampart:timestampmaxskew>300</rampart:timestampmaxskew>
<rampart:timestampstrict>false</rampart:timestampstrict>
<rampart:ReplayDetection>1000</rampart:ReplayDetection>
</rampart:rampartconfig>

If you are using rampart-1.2 you will have to implement the replay detection in your service.
The incoming TimeStamp information is available in the Security header processing results included in the message context properties under the key "org.apache.ws.security.handler.WSHandlerConstants.RECV_RESULTS". This is a Vector, and the first item of this is a "org.apache.ws.security.handler.WSHandlerResult" instance (wsResult in the next code snippet).
Then you can obtain the timestamp information as shown below:
actionResult = WSSecurityUtil.fetchActionResult(wsResult,
WSConstants.TS);
if (actionResult != null) {
Timestamp timestamp = actionResult.getTimestamp();
//Your validation goes here...
}
As suggested by the blog post you referenced you can try upgrading to rampart-1.6.2 and using the policy based configuration.

Related

Grails 3 and Spring Security: return 401 when user is not logged in

In my Grails 3.2.9 web-app I'm using Spring Security plugin to manage user session. This is the depencency:
compile "org.grails.plugins:spring-security-core:3.1.1"
The natural (years-long) evolution of the app brought to have basically all actions in all controllers, mostly secured using #Secured annotations, to return a JSON, with something like
return map as JSON // grails.converters.JSON
That means that all actions are basically acting like APIs.
But since they're secured, when user is not logged, a redirect is performed to /login/auth (login page), which is something you wouldn't expect. This is why I'm searching for a way to return 401 unauthorized status instead of letting Spring Security perform a redirect.
So far I've looked into pessimistic lockdown, and searches across the web also lead me to Spring Security Core REST plugin, but both ways don't seem to adapt to my case (to me at last, but maybe I'm missing something).
So any suggestion is welcome, thanks in advance!
Register the following in resources.groovy
authenticationEntryPoint(Http401AuthenticationEntryPoint, 'Bearer')
I do not have experience in Grails but perhaps what you are looking for can be implemented by providing a different implementation of org.springframework.security.web.AuthenticationEntryPoint in your Spring security configuration. By default for form authentication Spring uses org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint which performs redirect to the given login page. On the other hand org.springframework.security.web.authentication.HttpStatusEntryPoint just returns the desired status.
In our project entry point is set in the old fashioned way through XML configuration:
<http pattern="/**" auto-config="false" entry-point-ref="yourAuthenticationEntryPoint">

Possible proxy issue with WSO2 API Manager

Whenever I try to add the following endpoint, "http://ws.cdyne.com/phoneverify/phoneverify.asmx", during the Managed API setup process and press the Test button I get an error on the server. ERROR - APIProviderHostObject Error occurred while connecting to backend : "stackOverflow preventing me from showing this link", reason: Connect to ws.cdyne.com:80 timed out
When I try this exact same process on a machine outside of our proxy it works fine. I have gone into the axis2.xml file and added proxy information and even went as far as installing cntlm and setting the proxy to localhost - same error.
I can browse to the above link just fine on this machine.
My environment is Windows 10.
I assume you talk about clicking the Test button when providing Backend Endpoint in API publisher.
The way that Test button works at the moment (as far as I understand) is that it invokes HTTP HEAD method on the endpoint provided (because according to RFC 2616, "This method is often used for testing hypertext links for validity, accessibility, and recent modification.")
Then it checks response. If response is valid or 405 (method not allowed), then the URL is marked as Valid.
Thus sometimes, if backend is not properly following RFC, you might get otherwise working URLs declared as Invalid during the test because of that improper HEAD response evaluation. Obviously, this is just a check for your convenience and you can ignore the check if you know the endpoint works for the methods and resources you need it to work.
So my advice would be to try ignoring the Test and just finishing setting up and publishing the API.
P.S. I am checking it on WSO2 API Cloud but behavior is identical to downloadable API Manager.

How do I get Basic Authentication, GlassFish, REST, and a single page application to all work together with my own login form?

I'm using Glassfish 4 as a server with an AngularJS app as a client. Glassfish is exposing a REST API via JAX-RS (Jersey). I'm using Basic Authentication over an HTTPS connection. I have my own login form and am setting the Authorization header in my REST requests via JavaScript. My issue is that if I use normal web.xml based permissions (<auth-constraint> inside <security-constraint>), the responses come back with 401 with a WWW-Authenticate header (if the credentials are bad). This forces the browser to do the Basic Authentication dialog instead of my own and it appears there is no viable cross browser work around available on the browser side to stop it. So I need to somehow suppress the 401/WWW-Authenticate response.
I stopped using the web.xml based permissions, because it seems it is the Servlet level that is doing the 401 stuff. I was able to get Jersey authentication working with a filter and turning on the "RolesAllowedDynamicFeature" feature (in a matter similar to Glassfish #RolesAllowed with custom SecurityContext). That seems to work great and returns 403 for bad credentials (and thus no browser dialog). However, when I call my EJB's, they do not see the custom security context and the user I have set, so I get permission exceptions. If it matters: the EJB's are in a jar, the Jersey stuff is in a war, and both of them and bundled together in an ear. From what I can gather the only way to have the EJB's properly process credentials is to use the web.xml stuff.
I seemed to have painted myself into a corner and do not see how to make this work. Perhaps I can back out and return to using web.xml based permissions and somehow filter the servlet responses to not return 401/WWW-Authenticate? If so I could not find out how to do that. Or is there some way I can set EJB's security context? Or something else entirely? I wouldn't think using AngularJS with GlassFish and a REST API and Basic Authentication would be very unique, how does anyone do this?
Since posting this question I have found info on implementing a Servlet filter and using that to try to change the 401 response to a different status code. However, the filter never gains control if you have <auth-constraint> in your web.xml and the request is not authorized, so that did not help me. I still could not prevent the 401 responses.
But now I think I finally found the answer. I removed the <auth-constraint> tag from web.xml. I changed the Servlet filter to now extract the AUTHENTICATION_HEADER on its own and decode it (via javax.xml.bind.DatatypeConverter). Next I call HttpServletRequest.login (on the request object) with the decoded username and password. I catch the ServletException if the username/password combination is bad and use HttpServletResponse.sendError to send SC_FORBIDDEN. If I have a good login I call doFilter to continue on with processing of the request, and call HttpServletRequest.logout when it returns.
If I do this in combination with RolesAllowedDynamicFeature and annotations on the Jersey routines everything seems to work including calls to EJB's with their own security annotations.
Side note: before settling on HttpServletRequest.login I had tried to use HttpServletRequest.authenticate followed by checking the returned boolean, but when you gain control in that case the response has already been committed to be 401 and you cannot change it. I even tried passing a HttpServletResponseWrapper to authenticate to stop the commit from happening, but authenticate seems to get the response object through some other means, it seems to ignore the one you pass it (I even tried passed null and it didn't even notice).

WSO2 API Manager - "Make this the default version" causes authentication errors?

I have an API that works no problem providing the "Make this the default version" checkbox isnt checked, once checked I get this error back
<ams:fault
xmlns:ams="http://wso2.org/apimanager/security">
<ams:code>900906</ams:code>
<ams:message>No matching resource found in the API for the given request</ams:message>
<ams:description>Access failure for API: xxxx/xxxx, version: v0.1 with key: xxxxxx</ams:description>
</ams:fault>
Is there something I have missed at all?
Thanks,
Ash.
EDIT - Extra Detail and Logs
TID[-1234] [AM] [2014-07-10 13:05:56,238] ERROR
{org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler}
- API authentication failure org.wso2.carbon.apimgt.gateway.handlers.security.oauth.OAuthAuthenticator.authenticate(OAuthAuthenticator.java:157)
org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler.handleRequest(APIAuthenticationHandler.java:92)
org.apache.synapse.rest.API.process(API.java:285)
org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:83)
org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:64)
org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:220)
org.apache.synapse.core.axis2.SynapseMessageReceiver.receive(SynapseMessageReceiver.java:83)
org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:344)
org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:168)
org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:744)
Please save and publish the API once you made the change to the API. This may be causing the issue.
Once you have published you should see 2 sets of production url (one with the version and one without the version). Please check if the same is available in the API store for your API.
You'll first want to turn on wire logs in that environment by editing your ../repository/conf/log4j.properties file and restarting the service. This will allow you to see the request headers for both the initial request to the gateway and the request from the gateway to itself (or other gateways in your cluster) since that's how requests to a default API version are resolved. This can help you identify whether your Authorization header values are actually making it to the authentication handler.
After you take a look at this, note that when you publish an API with a default version, you're actually creating (or updating) two separate synapse configurations for the API: a versioned configuration and an unversioned configuration. The portion of the latter's definition that you need to check is:
<else>
<header name="WSO2_AM_API_DEFAULT_VERSION" scope="transport" value="true"/>
<property name="uri.var.portnum" expression="get-property('https.nio.port')"/>
<send>
<endpoint>
<http uri-template="https://localhost:{uri.var.portnum}/myApi/v1">
<timeout>
<duration>60000</duration>
<responseAction>fault</responseAction>
</timeout>
</http>
</endpoint>
</send>
</else>
By default, the newly generated definition for the default version attempts to send the request to localhost, which may not be what you want. Check at ../repository/deployment/synapse-configs/default/api and make sure that this definition is correct.
Since it looks like this is actually an authentication error, you should also test a new subscription. Create a new application with some subscriber, subscribe to the API, and generate new access tokens. I wouldn't understand why (since setting a default version doesn't create a new API entry in the AM_API table) but this could possibly be due to the access token credentials being invalid for the default version, and generating new tokens should (in theory) test against this.

Fileupload authentication issue on Websphere 7

We are currently facing a production issue on Websphere 7 with respect to richfaces fileupload component. The problem description is that immediately after the file for upload is browsed and selected using this component, the basic authentication dialogbox appears asking for user credentials.
Following are the frameworks we are using in our project:
JSF 1.2 & Richfaces 3.3.3
Spring Framework 3.x
Spring Webflow 2.1
Spring Security 3.x (only basic authentication using login dialogbox)
The user is authenticated once when he wants to access the application at the beginning using basic authentication. All screens that dont use fileupload component are working fine. But if we use fileupload component, as I mentioned above, the file selection (even from local machine path) triggers the basic authentication dialogbox again. The strange thing is that this behaviour does not occur on our Dev Environment which uses Tomcat 6. On Tomcat, the fileupload is not triggering any user login and upload is working fine.
This problem is occuring only when the app. is deployed on Websphere 7. Can anybody please tell whether Websphere requires any additional configuration for accessing Files through this component ?
We have spent a lot of time investigating this problem without any meaningful results. As this is a production issue for us now, it is very critical and needs to be resolved at the earliest.
So please help in this regard. Thanks in advance.
I don't know the File Upload component, and the answer may well lie in the detail of how that works, but in general WebSphere will challenge if an HTTP request arrives for a protected resource and the request does not contain a valid LTPA cookie. The cookie is normally sent by the browser on each request when authentication has happended once, BUT it will only do so if it believes that the cookie is related to a given domain. So if the main part of your website were served from, say,
htpp://my.own.org.com/mysite
and the file upload were related to a subtly different host
http://my.other/filesite
Then the cookie would not be sent, and a challenge would result.
My approach to diagnosing this would be get some kind of traffic sniffer. See exactly what is flowing and the addresses being used. I'm predicting that you will see the LTPA cookie in the usual case and not in the upload case. Then it's a matter of figuring out "why".