cancel
Showing results for 
Search instead for 
Did you mean: 

odata4j and CSRF-Token

stefan_heitzer
Participant
0 Kudos

Hi everybody,

I'm trying to make a CREATE-Request to SAP Netweaver Gateway.

The frontend program is and android application which is using the odata4j library.

When I call the CREATE-Request I always got the error "Validation of CSRF-Token failed"... so I searched a bit and found that you need to fetch the CSRF-Token first and put it as a separate header.

The coding seems to work and looks like the following:


public class SAPCSRFBehavior implements JerseyClientBehavior {

    private String xcsrfToken = "";

   

    @Override

    public ODataClientRequest transform(ODataClientRequest request) {

        if(request.getMethod().equals("GET")){

            request = request.header("X-CSRF-Token", "Fetch");

            return request;

        }else{

            request = request.header("X-CSRF-Token", this.xcsrfToken);

            return request;

        }

       

    }

    @Override

    public void modify(ClientConfig arg0) {

        // TODO Auto-generated method stub

       

    }

    @Override

    public void modifyClientFilters(Filterable client) {

        client.addFilter(new ClientFilter(){

            @Override

            public ClientResponse handle(ClientRequest clientRequest)

                    throws ClientHandlerException {

                ClientResponse response = this.getNext().handle(clientRequest);

                MultivaluedMap<String, String> headers = response.getHeaders();

                xcsrfToken = headers.getFirst("X-CSRF-Token");

                System.out.println("Token: " + xcsrfToken);

                return response;

            }

         });

    }

    @Override

    public void modifyWebResourceFilters(Filterable arg0) {

        // TODO Auto-generated method stub

       

    }

}

When I log the Token I'll get a valid value for it ... but ... somehow I simply get the same error message as before

I really hope somebody has a solution for the problem ... Looking really forward to hearing from you!

Greetings

Stef

Accepted Solutions (0)

Answers (2)

Answers (2)

stefan_heitzer
Participant
0 Kudos

Some news:

I tried it again and found out that somehow in the POST request the CSRF-Token is not sent. When I look at the console I always get as value "required" ...

0 Kudos

Hi Stefan,

did you solve your problem ? I'm in the same situation as you, I receive the same message: x-csrf-token: "Required", but I'm setting it following this SCN Thread:

Hope you can help me.

Thank you very much.

Carlos.

0 Kudos

I can finally do PUT (update) and CREATE Operations to SAP Netweaver Gateway from Android native app using odata4j:

I solved my problem following this SAP SCN thread:

SAP Fiori LL16 - http 403 Forbidden CSRF token error

After that, I put these headers at ODataClientRequest:

request = request.header("X-Requested-With", "XMLHttpRequest")

                                .header("Authorization", "Basic " + encoded);

Then, you don't need to implement any SAPCSRFBehaviour class that gets the csrf token from GET requests. Only with that two headers is enough.

With this configuration I didn't receive again the 403 Forbidden error.

Hope this can help anyone.

Carlos.

ginwene_rueda
Participant
0 Kudos

Hi Carlos,

Can you provide the sample code for your POST and PUT request?

I did what you mentioned with regards to disabled CSRF token, but I still got 403 from Android.

I also tested the same payload, request method and it works on REST client, can you shed some light on what's missing on my implementation?

0 Kudos

Hi Ginwene,

Here is the commented code, hope it helps you:

ODataJerseyConsumer consumer = ODataJerseyConsumer.create(serviceUrl);

ODataJerseyConsumer.Builder builder = ODataJerseyConsumer.newBuilder(serviceUrl);

              

                // Authentication

                builder.setClientBehaviors(new OClientBehavior(){           

                         @Override

                         public ODataClientRequest transform(ODataClientRequest request) {

                            String userPassword = "USEREXAMPLE" + ":" + "passexample";

                            String encoded = Base64.encodeBase64String(userPassword.getBytes());

                            encoded = encoded.replaceAll("\r\n?", "");

                                   

                             // Necessary headers to do PUT and POST operations

                            request = request.header("X-Requested-With", "XMLHttpRequest")

                                             .header("Authorization", "Basic " + encoded);      

                                           

                            return request;

                      }});

                consumer = builder.build();

              

                // LOG HTTP

                consumer.dump.all(true);             

              

                // CREATE ENTITY

                consumer.createEntity("matrset")

                            .properties(OProperties.string("Material", "30"))

                            .properties(OProperties.string("MatlDesc", "Nuevo Material Android 3"))

                            .properties(OProperties.string("Langu", "S"))

                            .properties(OProperties.string("IndSector", "C"))

                            .properties(OProperties.string("MatlType", "ZSTD"))

                            .properties(OProperties.string("MatlGroup", "1130"))

                            .properties(OProperties.string("BaseUom", "KG")).execute();

                                      

                // UPDATE ENTITY

                OEntity entityToUpdate = consumer.getEntity("matrset", "35").execute();

   

// UPDATE ENTITY OPERATION (PUT)        

consumer.updateEntity(entityToUpdate).properties(OProperties.string("MatlDesc","Descripcion Nueva de Material 2"))

                                                     .properties(OProperties.string("Langu","S")).execute();

ginwene_rueda
Participant
0 Kudos

Hi Carlos,

Here's my application code:

ODataJerseyConsumer consumer = ODataJerseyConsumer.create(SERVICE_URL);
ODataJerseyConsumer.Builder builder = ODataJerseyConsumer.newBuilder(SERVICE_URL);

// Basic Authentication Consumer
builder.setClientBehaviors(new OClientBehavior() {
     @Override
     public ODataClientRequest transform(ODataClientRequest oRequest) {
          String userPassword = "USER" + ":" + "PASSWORD";
          String encoded = Base64.encodeBase64String(userPassword.getBytes());
          encoded = encoded.replaceAll("\r\n?", "");

          oRequest = oRequest
                    .header("X-Request-With", "XMLHttpRequest")
                    .header("Content-Type", "application/atom+xml;type=entry")
                    .header("Authorization", "Basic " + encoded);
          return oRequest;
     }
});

consumer = builder.build();

// Outputs all http request
consumer.dump.all(true);

// POST and no identifier since new user account
consumer.createEntity("UserProfileSet")
          .properties(OProperties.string("ProfileCode", "EXECUTIVE"))
          .properties(OProperties.string("User", "MY_EMAIL"))
          .execute();

I'm using 0.7 odata4j, inside an asyncTask for background processing and running in an emulator.

All GET method are working, except for POST and PUT.

Thanks,

Gin

stefan_heitzer
Participant
0 Kudos

After testing around a bit and setting some messages in the console it seems that the token isn't set for the POST request???? ....

I also read something about setting special CookieValues ... but I don't have a cookie.

kammaje_cis
Active Contributor
0 Kudos

I have not worked on OData4j. But did you try this?

That seems detailed.

Also, have you tested the Gateway service using a browser client and ensure that it works as expected?

regards

Krishna

stefan_heitzer
Participant
0 Kudos

Hey Krishna,

thx for your reply! I've already found this blog post and did exactly the same ... the problem which I have is that I don't have any cookies available at the response and also not at the request ... I receive the CSRF-Token but it seems that it isn't sent with the CREATE-request.

I've tried to test it yeah ... but it is not quite easy to teast a CREATE-request with a browser tool or is there a specifig possibility???

Greetings

Stef

kammaje_cis
Active Contributor
0 Kudos

You can easily test it with REST clients like POSTMAN. All you have to do is do a read request first,  get the token, use that token for Create. Read response can be used as request body for create.

You can also test it using SAP Gateway client. See here.

stefan_heitzer
Participant
0 Kudos

Well what I did so far was to test a GET and a POST request ... and it actually seemed to work because I took the token from the GET request and set it as a x-csrf-token header in the POST request --> the error message "validation of csrf failed" disappeared.

But when I test it with odata4j ... the error message is still there