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

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.

Related

401 Error, Mule while Username/Password are Correct

I am trying to use postman to call an API that I have deployed with Mule. I have downloaded this API from a trusted source (Collibra) and thus expect it to be in working condition.
The API Request:
http://localhost:8081/connect/dgc/export/asset?filter=name%20STARTS_WITH%20E
Here is the Basic Auth setup in one of the xml files.
<mule-ss:security-manager name ="authenticationManager" doc:name="Spring Security Provider">
<mule-ss:delegate-security-provider
name="memory-provider" delegate-ref="authenticationManager-common" />
</mule-ss:security-manager>
<spring:beans>
<ss:authentication-manager alias="authenticationManager-common">
<ss:authentication-provider>
<ss:user-service id="userService">
<ss:user name="${service.user}" password="${service.password}"
authorities="ROLE_ADMIN" />
</ss:user-service>
</ss:authentication-provider>
</ss:authentication-manager>
</spring:beans>
And here is the setting of the username/password in a properties file.
service.user=user
service.password=password
The following error appears when I make a postman GET request with the correct credentials.
Failed to connect/reconnect: Work Descriptor. Root Exception was: Unexpected response with status code: 401 was returned. Message was: {"statusCode":401,"titleMessage":"Not authorized","userMessage":"The user name or password is wrong. Try again."}
And here is the error that appears if I use the incorrect credentials.
Root Exception stack trace:
org.springframework.security.authentication.BadCredentialsException: Bad credentials
What could be going wrong to have the error appear when I am passing the correct credentials through the Basic Auth? I have double-checked the string with an online header generator and it is indeed correct.
It is difficult to troubleshoot without understanding the API implementation, but given the error with incorrect credentials seems to come from the Spring Security Manager and with the correct credentials it looks to be connecting to something else, it is possible that the API is calling some backend system or API and failing to authenticate to it.

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 is not responding to a request that returns zip file (application/octet-stream)

Using WSO2 API Manager 1.3.1. Trying to use the API Manager to proxy to a REST service. I have set up the service in API Mgr and can successfully post and get responses, typically json, though some are text.
However, when I try to GET a resource that returns binary content (a zip "file", content-type:application/octet-stream), the API Manager does not seem to respond and I can see an error in the console window (i'm running wso2server.bat in console):
[2013-07-03 11:52:05,048] WARN - SourceHandler Connection time out
while writing the response: 173.21.1.22:1268->173.21.1.22:8280
I have an HTTPModule on my internal service and it seems to be responding with the appropriate content (I can see the GET and response data logged). I can also call to the internal service directly and get a response, so that end of things seems OK. But going through the API Manager seems to fail.
I found information on enabling other content-types:
WSO2 API Manager - Publishing API with non-XML response
http://wso2.com/library/articles/binary-relay-efficient-way-pass-both-xml-non-xml-content-through-apache-synapse
Using that information I tried to enable the application/octet-stream for messageFormatter and messageBuilder using the binary relay and it did not help (or seem to make a difference). I have even disabled all other content-types and use the binary relay for all content-types and it does not help.
Currently, I'm running with just the following in both axis2.xml and axis2_client.xml (in their appropriate sections):
<messageBuilder contentType=".*" class="org.wso2.carbon.relay.BinaryRelayBuilder"/
<messageFormatter contentType=".*" class="org.wso2.carbon.relay.ExpandingMessageFormatter"/>
I still get my json and text responses, but WSO2 times out getting the zip content. I saw the JIRA referenced in axis2.xml about enabling the ".*" relay, but as the other requests seem to work, I'm not sure it's an issue for me. I did try adding
'format="rest"' to the API definition, but it seemed to break all operations even the ones that worked prior so I've pulled it back out.
Any ideas on what is happening or how to dig in and debug this will help. Thanks!
After working with this for much too long, it turns out that my WSO2 configuration was correct, using the Message Relay and BinaryRelayBuilder, etc. While my REST service could reply immediately, I was setting a HTTP header that I assume WSO2 does not like, because when i removed it WSO2 would reply at an expected rate (instantly).
I was setting the header:
Transfer-Encoding: binary
When I removed that header from my service reply, then WSO2 operated as expected. I don't know if that's a "bug" in WSO2 or if I was implementing incorrectly, but I do have what seems like a "workaround" by omitting that header from my service response.

Apache axis2 and Rampart not preventing 'replay attacks'

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.