Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
joachimvanpraet
Active Participant

In this blog I will give a simple example on how to use a captcha in ABAP Webdynpro.

Architecture

We generate a simple string in ABAP and send it to a servlet on a J2EE server. This servlet generates an image with SimpleCaptcha. http://simplecaptcha.sourceforge.net/ . The generated images is received on the ABAP stack and copied to a cached response so the captchastring is not in the url of the image.

The source of the java application can be downloaded here. (tested on SAP NW 7.31 SP5)

Captcha Servlet

This is a simple servlet application that generates a captcha image from a given string.

1.       Download the simplecaptcha library

2.       Create an external library DC and name it captcha/lib

3.       Add the simplecaptcha jar-file to the libraries folder

4.       Add the jar-files to the public part of the library

5.       Create a new web module development component and name it captcha

6.       Add a DC dependency between the web module and the library

7.       Add a new servlet and give it a name and package

8.       Copy the simplecaptcha.jar to the WEB-INF/lib directory

9.       Enter the following code:

package com.flexso.captcha;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.flexso.captcha.noise.CustomNoiseProducer;
import nl.captcha.Captcha;
import nl.captcha.servlet.CaptchaServletUtil;
import java.awt.Color;
import java.awt.Font;
public class CaptchaImage extends HttpServlet {
          private static final long serialVersionUID = 1L;
            private static int _width = 180;
            private static int _height = 60;
            private static final List<Color> COLORS = new ArrayList<Color>(2);
            private static final List<Font> FONTS = new ArrayList<Font>(3);
            static {
                        COLORS.add(Color.BLACK);
                        COLORS.add(Color.BLUE);
                        FONTS.add(new Font("Geneva", 2, 48));
                        FONTS.add(new Font("Courier", 1, 48));
                        FONTS.add(new Font("Arial", 1, 48));
                      }
    public CaptchaImage() {
        super();
    }
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                    response.setContentType("image/png");
                    response.setCharacterEncoding("UTF-8");
                    String word = request.getParameter("captcha");
                    WordGenerator wordRenderer = new WordGenerator(word);
                    Captcha captcha = new Captcha.Builder(_width, _height).addText(wordRenderer)
                .gimp()
                .addNoise())
                .build();
              CaptchaServletUtil.writeImage(response, captcha.getImage());
          }
}

10.   Add a class WordGenerator to be able to decide which word will be used to generate the captcha image.

package com.flexso.captcha;
import nl.captcha.text.producer.TextProducer;
public class WordGenerator implements TextProducer
{
  private String text = "";
  public WordGenerator(String text){
            this.text = text;
  }
  public String getText(){
    return this.text;
  }
}

11.   Adapt the web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>LocalDevelopment~captcha~flexso.com</display-name>
  <servlet>
    <description></description>
    <display-name>CaptchaImage</display-name>
    <servlet-name>CaptchaImage</servlet-name>
    <servlet-class>com.flexso.captcha.CaptchaImage</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CaptchaImage</servlet-name>
    <url-pattern>/captcha.png</url-pattern>
  </servlet-mapping>
</web-app>

12.   Create an enterprise application DC with the name captcha/ear

13.   Add the web module to the captcha/ear project

14.   Adapt the application.xml

<?xml version="1.0" encoding="ASCII"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" version="5">
  <display-name>LocalDevelopment~captcha~ear~flexso.com</display-name>
  <module>
    <web>
      <web-uri>flexso.com~captcha.war</web-uri>
      <context-root>captcha</context-root>
    </web>
  </module>
</application>

15.   Deploy the ear file.

16.   Test the captcha http://<portalserver>:<port>/captcha/captcha.png?captcha=test

ABAP Webdynpro application

In the ABAP WD application we build a random string to send to the captcha application.

We request the captcha image  on the ABAP server and provide it in a cached response to our webdynpro application to hide the captcha string in the url.

1.       Create a new web dynpro component

2.       In the component controller create a context node CAPTCHA with 3 strings: SOURCE, ANSWER, IMAGE.

3.       Create method generate_captcha in the component controller. In this method we create a random string, with this string we build the url to the J2EE server to generate the captcha image. At the end of the method we copy the image from the java server to a cached response on the ABAP stack and then we fill the context. This is the code:

method GENERATE_CAPTCHA .
  CONSTANTS: CO_ALFABET type CHAR30 VALUE 'abcdefghijklmnopqrstuvwxyz'.
  DATA: lv_captcha type CHAR08,
        lv_i   type i,
        lv_char type CHAR01,
        lv_seed type i,
        lo_ran type ref to cl_abap_random_int,
        lv_url type string,
        lv_length type i value 8.
*   generate a random string with length lv_length
  lv_seed = sy-timlo.
  lv_i = STRLEN( co_alfabet ) - 1.
  lo_ran = cl_abap_random_int=>create( min = 0 max = lv_i seed = lv_seed ).
  DO lv_length TIMES.
    lv_i = lo_ran->get_next( ).
    lv_char = CO_ALFABET+lv_i(1).
    lv_i = lo_ran->get_next( ).
    if lv_i MOD 2 = 0 .
      TRANSLATE lv_char TO UPPER CASE.
    endif.
    CONCATENATE lv_captcha lv_char into lv_captcha.
  ENDDO.
*   build url to generate captcha image
  CONCATENATE '/captcha/captcha.png?captcha=' lv_captcha into lv_url.
  lv_url = wd_this->GET_CACHED_URL( lv_url ).
  " Set data in context
  DATA lo_nd_captcha TYPE REF TO if_wd_context_node.
  DATA lo_el_captcha TYPE REF TO if_wd_context_element.
  DATA ls_captcha TYPE wd_this->Element_captcha.
  lo_nd_captcha = wd_context->get_child_node( name = wd_this->wdctx_captcha ).
  lo_el_captcha = lo_nd_captcha->get_element( ).
  lo_el_captcha->set_attribute( name =  `SOURCE` value = lv_captcha ).
  lo_el_captcha->set_attribute( name =  `IMAGE` value = lv_url ).
endmethod.

4.       To copy the image from the JAVA response to the ABAP response I created a separate method GET_CACHED_URL. Importing parameter IV_URL (STRING) and returning parameter OV_URL(STRING)

method GET_CACHED_URL .
  DATA : lo_http_client TYPE REF TO if_http_client,
         lo_cached_response TYPE REF TO IF_HTTP_RESPONSE,
         lv_image TYPE xstring,
         lv_guid TYPE GUID_32.
  " read the image on the java server
  CALL METHOD cl_http_client=>create_by_url
    EXPORTING
      url    = 'http://<javaserver>:<port>'
    IMPORTING
      client = lo_http_client
    EXCEPTIONS
      OTHERS = 1.
  CALL METHOD lo_http_client->request->set_header_field
    EXPORTING
      name  = '~request_uri'
      value = iv_url.
  CALL METHOD lo_http_client->send
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3.
  CALL METHOD lo_http_client->receive
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3.
  lv_image = lo_http_client->response->get_data( ).
  " send the image to the cached response on the ABAP server
  CREATE OBJECT lo_cached_response TYPE CL_HTTP_RESPONSE EXPORTING ADD_C_MSG = 1.
  " SET IMAGE TO MIME
  lo_cached_response->SET_DATA( lv_image ).
  lo_cached_response->SET_HEADER_FIELD( NAME = IF_HTTP_HEADER_FIELDS=>CONTENT_TYPE VALUE = 'image/png' ).
  lo_cached_response->SET_STATUS( CODE = 200 REASON = 'OK' ).
  lo_cached_response->SERVER_CACHE_EXPIRE_REL( EXPIRES_REL = 100 ).
  " generate an url
  CALL FUNCTION 'GUID_CREATE'
    IMPORTING
      EV_GUID_32 = lv_guid.
  CL_WD_UTILITIES=>CONSTRUCT_WD_URL( EXPORTING
  APPLICATION_NAME = 'Z_CAPTCHA' "WEBDYNPRO APPLICATION NAME
  IMPORTING OUT_LOCAL_URL = OV_URL ).
  CONCATENATE OV_URL '/' lv_guid sy-uzeit '.png' INTO OV_URL.
  CL_HTTP_SERVER=>SERVER_CACHE_UPLOAD( URL = OV_URL RESPONSE = lo_CACHED_RESPONSE ).
endmethod.

5.       Open the view of the webdynpro

6.       In the context tab, bind the CAPTCHA node from the componentcontroller.

7.       In the layout tab add following elements to the view:

     a.       An image and bind the source property to attribute IMAGE af the CAPTCHA node.

     b.      An input field and bind the property value to attribute ANSWER of the CAPTCHA node.

     c.       A button ‘check captcha’ and assign an action CHECK

     d.      A button refresh and assign an action REFRESH

8.       Implement the 2 actionhandlers

method ONACTIONCHECK.
    DATA lo_nd_captcha TYPE REF TO if_wd_context_node.
    DATA lo_el_captcha TYPE REF TO if_wd_context_element.
    DATA ls_captcha TYPE wd_this->Element_captcha.
*     get message manager
    data lo_api_controller     type ref to if_wd_controller.
    data lo_message_manager    type ref to if_wd_message_manager.
    data: lv_Str type string,
          lv_text type string,
          lv_type type I.
    " read context
    lo_nd_captcha = wd_context->get_child_node( name = wd_this->wdctx_captcha ).
    lo_el_captcha = lo_nd_captcha->get_element( ).
    lo_el_captcha->get_static_attributes( IMPORTING static_attributes = ls_captcha ).
    " get message manager
    lo_api_controller ?= wd_This->Wd_Get_Api( ).
    CALL METHOD lo_api_controller->GET_MESSAGE_MANAGER
      RECEIVING
        MESSAGE_MANAGER = lo_message_manager
        .
    lv_type = IF_WD_MESSAGE_MANAGER=>CO_TYPE_ERROR.
    lv_text = 'ERROR!'.
    TRANSLATE LS_CAPTCHA-SOURCE TO UPPER CASE.
    TRANSLATE LS_CAPTCHA-ANSWER TO UPPER CASE.
"   compare captcha answer with the source
    if LS_CAPTCHA-SOURCE = LS_CAPTCHA-ANSWER.
      lv_type = IF_WD_MESSAGE_MANAGER=>CO_TYPE_STANDARD.
      lv_text = 'OK!'.
    endif.
*     report message
    CALL METHOD lo_message_manager->REPORT_MESSAGE
      EXPORTING
        MESSAGE_TEXT              = lv_text
        MESSAGE_TYPE              = lv_type
      RECEIVING
        MESSAGE_ID                = lv_str
        .
endmethod.
method ONACTIONREFRESH .
  WD_COMP_CONTROLLER->GENERATE_CAPTCHA( ).
endmethod.

Create a web dynpro application object and test the application!

Result:

15 Comments
Labels in this area