I am trying to implement Basic Auth
in WSO2 EI 6.5.0.
Below mentioned Class Mediator code is bundled and placed it into <WSO2EI_HOME>/lib
and product restart done.
CustomBasicAuth:
package com.basic.auth.handler;
import org.apache.commons.codec.binary.Base64;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.core.axis2.Axis2Sender;
import org.apache.synapse.rest.Handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Map;
public class CustomBasicAuth implements Handler {
private static final Log log = LogFactory.getLog(CustomBasicAuth.class);
public void addProperty(String s, Object o) {
//To change body of implemented methods use File | Settings | File Templates.
}
public Map getProperties() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public boolean handleRequest(MessageContext messageContext) {
log.info("Inside CustomBasicAuth Class **** " );
org.apache.axis2.context.MessageContext axis2MessageContext
= ((Axis2MessageContext) messageContext).getAxis2MessageContext();
Object headers = axis2MessageContext.getProperty(
org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
if (headers != null && headers instanceof Map) {
Map headersMap = (Map) headers;
if (headersMap.get("Authorization") == null) {
headersMap.clear();
axis2MessageContext.setProperty("HTTP_SC", "401");
headersMap.put("WWW-Authenticate", "Basic realm=\"WSO2 ESB\"");
axis2MessageContext.setProperty("NO_ENTITY_BODY", new Boolean("true"));
messageContext.setProperty("RESPONSE", "true");
messageContext.setTo(null);
Axis2Sender.sendBack(messageContext);
return false;
} else {
String authHeader = (String) headersMap.get("Authorization");
if (processSecurity(authHeader)) {
return true;
} else {
headersMap.clear();
axis2MessageContext.setProperty("HTTP_SC", "403");
axis2MessageContext.setProperty("NO_ENTITY_BODY", new Boolean("true"));
messageContext.setProperty("RESPONSE", "true");
messageContext.setTo(null);
Axis2Sender.sendBack(messageContext);
return false;
}
}
}
return false;
}
public boolean handleResponse(MessageContext messageContext) {
return true;
}
public boolean processSecurity(String credentials) {
log.info("encoded credentials**** " + credentials);
String decodedCredentials = new String(new Base64().decode(credentials.getBytes()));
log.info("decoded Credentials**** " + decodedCredentials);
String username = decodedCredentials.split(":")[0];
String password = decodedCredentials.split(":")[1];
if ("wso2user".equals(username) && "wso2user".equals(password)) {
return true;
} else {
return false;
}
}
}
When I invoke API, below ERROR found in wso2carbon
log file
Wire Log:
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "POST /basicauthapi HTTP/1.1[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Authorization: Basic d3NvMnVzZXI6d3NvMnVzZXI=[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Type: application/json[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "User-Agent: PostmanRuntime/7.30.0[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept: */*[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Cache-Control: no-cache[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Postman-Token: 330c0efb-1ded-41ca-b078-81a0869604a5[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Host: 192.168.43.128:8281[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Encoding: gzip, deflate, br[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Connection: keep-alive[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Length: 22[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "{[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> " "Test":"API"[\r][\n]"
[2023-01-16 17:21:26,873] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "}"
[2023-01-16 17:21:26,904] [] ERROR - ServerWorker Error processing POST request for : /basicauthapi.
java.lang.ArrayIndexOutOfBoundsException: 1
at com.basic.auth.handler.CustomBasicAuth.processSecurity(CustomBasicAuth.java:73)
at com.basic.auth.handler.CustomBasicAuth.handleRequest(CustomBasicAuth.java:47)
at org.apache.synapse.rest.API.process(API.java:357)
at org.apache.synapse.rest.RESTRequestHandler.apiProcess(RESTRequestHandler.java:135)
at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:113)
at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:71)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:325)
at org.apache.synapse.core.axis2.SynapseMessageReceiver.receive(SynapseMessageReceiver.java:92)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:338)
at org.apache.synapse.transport.passthru.ServerWorker.processEntityEnclosingRequest(ServerWorker.java:383)
at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:152)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "HTTP/1.1 500 Internal Server Error[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Content-Type: application/json; charset=UTF-8[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Date: Mon, 16 Jan 2023 11:51:26 GMT[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Transfer-Encoding: chunked[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Connection: keep-alive[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "46[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "{"Fault":{"faultcode":"soapenv:Server","faultstring":1,"detail":null}}[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "0[\r][\n]"
[2023-01-16 17:21:26,920] [] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
WSO2 EI API:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/basicauthapi" name="BasicAuthAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<log level="custom">
<property name="====BasicAuthAPI" value="caleed====="/>
</log>
<payloadFactory media-type="json">
<format>{"Status":"success"}</format>
<args/>
</payloadFactory>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
<handlers>
<handler class="com.basic.auth.handler.CustomBasicAuth"/>
</handlers>
</api>
POSTMAN HIT:
Please let me know why custom basic auth not working.
When you extract the Auth header like String authHeader = (String) headersMap.get("Authorization");
you will get the value as Basic d3NvMnVzZXI6d3NvMnVzZXI=
. This is not a valid Base64 encoded value, hence when you try to decode the value (new Base64().decode(credentials.getBytes())
) it's failing, eventually throwing an error when trying to split(decodedCredentials.split(":")[0]
) the credentials string.
So from the Auth header, you need to extract the credentials part. Multiple ways to do this. Following is using substring. Update the credentials extraction part to following.
String authHeader = (String) headersMap.get("Authorization").substring(6).trim();
On a different note, this code needs improvements and better error handling. For example, what if the Header is invalid? What if the password/username is missing? What if the encoding is wrong?
Update
It seems the product already packs a Auth handler by default. Which authenticates using the connected userstore. Hence you should be able to use this as well.
<handlers>
<handler class="org.wso2.carbon.integrator.core.handler.RESTBasicAuthHandler"/>
</handlers>