Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Ani_Koycheva
Employee
Employee
0 Kudos

The change is introduced in SAP NetWeaver 7.5 SP_COR (SP25) code line.

3154658-Missing Authorization check in SAP NetWeaver Application Server for Applocking service


Following actions have been introduced:

  • logical_locking_create
  • app_locking_administrative

 


Following roles have been introduced:

  • APP_LOCKING_CREATE
    • Action logical_locking_create is assigned to this role and is needed to invoke LogicalLockingFactory.createLogicalLocking(..).
  • APP_LOCKING_ADMIN
    • Action app_locking_administrative and action logical_locking_create  are assigned to this role and is needed to use LogicalLockingFactory.createLogicalLocking(..) and AppLockingRuntimeInterface methods.

Following roles have been extended:

  • Administrator - action logical_locking_create and action app_locking_administrative are assigned to this role.

Following property has been added to Applocking service:

  • secureMode - with predefined values - Off / On / Preview. 
    • Off - reverts the old behavior without any checks;
    • On - full security is enabled. I.e. guest/anonymous users are not allowed, only users with required roles will be allowed to use the functionality;
    • Preview - Similar to “On” but instead of breaking the functionality only exception with severity “Error” will be logged in the defaultTrace files, allowing the customers to adopt to the new changes;

  • The property is offline modifiable (i.e. requires AS Java restart) and will be added in "Expert" view

    Default value for the property:

    • At the beginning it will be set to Off until the internal adoption is finished (7.50 SP25). No documentation for the customers will be available. It is not expected for the customers to know about the new behavior;
    • After finishing with internal adoption the value will be set to Preview (7.50 SP26) which will allow the customers to adopt to the new functionality. Technical note for customers will support this activity;
    • Finally the property will be set to On (7.50 SP 27) at that time few issues should be handled;

No roles are needed in the following cases:

  1. AppLockingRuntimeInterface methods are called in system thread.
  2. AppLockingRuntimeInterface methods are called with a user under Administrator role.
  3. New LogicalLockingFactory is created in system thread.
  4. New LogicalLockingFactory is created with user under Administrator role.

Unauthorized user will receive an exceptions similar to this one:

EXCEPTION]
java.lang.SecurityException: The user does not have permission: applocking, Action: logical_locking_create
at com.sap.engine.services.applocking.AppLockingAccessPermissionProvider.checkAccessPermission(AppLockingAccessPermissionProvider.java:20)
at com.sap.engine.services.applocking.LogicalLockingFactoryImpl.createLogicalLocking(LogicalLockingFactoryImpl.java:43)
at sun.reflect.GeneratedMethodAccessor498.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)


Which are the affected methods:

1.LogicalLockingFactory methods are protected. If you lookup "/LogicalLockingFactory" you should adopt your application.

      createLogicalLocking(...)

2. AppLockingRuntimeInterface methods are protected.  If you look up "/applocking" you should adopt your application.

      registerManagementListener(...)
      getTimeStatisticsEntries()
      enableTimeStatistics()
      disableTimeStatistics()
      resetTimeStatistics()
      getLifetimeDescriptions()
      getLifetimeDescriptionsAsProperties()
      getTimeStatisticsEntriesAsProperties()

 

How to adopt the Applocking authorization change:

Define a new role or reuse the predefined one:

  • Define the new role in SDA META-INF/actions.xml or META-INF/authorization-configuration.xml file. If you use Japro, the file path is psrv/server/descriptors/authorization-configuration.xml (BeginPrimaryServiceComponent) or ear/dist/META-INF/actions.xml (BeginJ2EEApplicationComponent).You can do this by adding the following: 

           <BUSINESSSERVICE NAME="COMPONENT NAME">
                <DESCRIPTION LOCALE="en" VALUE="COMPONENT_DESCRIPTION"/>

                <ACTION NAME="logical_locking_create">
                     <DESCRIPTION LOCALE="en" VALUE="Allows calls to create logical locking, i.e. to call LogicalLockingFactoryImpl.createLogicalLocking(...)"/>
                    <PERMISSION CLASS="com.sap.engine.services.applocking.AppLockingAccessPermission" NAME="applocking" VALUE="logical_locking_create"/>
                </ACTION>

                <ROLE NAME="SOME_ROLE_NAME">
                    <ASSIGNEDACTION NAME="logical_locking_create"/>
                </ROLE>
            </BUSINESSSERVICE>

OR

  • Assign one of the following roles to the calling user
    • APP_LOCKING_CREATE
    • APP_LOCKING_ADMIN

Assign this role to an existing user:

  • Use useradmin
  • Create/assign it programmatically

    private void createAssignUser() throws UMException {
        IServiceUserFactory userFactory = UMFactory.getServiceUserFactory();
        IRoleFactory rf = UMFactory.getRoleFactory();

        // Get the desired role
        IRole role = rf.getRoleByUniqueName(DESIRED_ROLE);
        String roleUniqueID = adminRole.getUniqueID();

        // Try to get the user
        IUser user= null;
        try {
            user= userFactory.getServiceUser(DESIRED_USER_NAME);
            
            // Add user to DESIRED_ROLE role if it is still not in this role
            boolean isMember = user.isMemberOfRole(roleUniqueID , true);
            if (!isMember) {
                rf.addUserToRole(user.getUniqueID(), roleUniqueID );
            }
        } catch (NoSuchUserException noSuchUserExc) {
            // The user doesn't exist, create it

            try {
                userFactory.createServiceUser(DESIRED_USER_NAME);
                user = userFactory.getServiceUser(DESIRED_USER_NAME);
                
                // Add user to DESIRED_ROLE role without a check.
                // If the user is created on another server node and it is still not
                // granted DESIRED_ROLE role we ensure here we are not going to 
                // use it before we grant it this role. Thus we do not need to have
                // special synchronization in cluster
                rf.addUserToRole(user.getUniqueID(), roleUniqueID);
            } catch (UserAlreadyExistsException uaex) {
                user = userFactory.getServiceUser(DESIRED_USER_NAME);
                boolean isMember = user.isMemberOfRole(roleUniqueID, true);
                if (!isMember) {
                    rf.addUserToRole(user.getUniqueID(), roleUniqueID);
                }
            }
        }
    }

Use the new user:

  • Programmatically 

Using Subject.doAs() method.  Run code with user which has desired role. Here is an example:

// Or create separate class
  PrivilegedExceptionAction codeToBeExecutedWithGivenUser = new PrivilegedExceptionAction() { public Object run() throws Exception { //Code to be executed with given user and return result return null; } };

IUser doAsUser = UMFactory.getUserFactory().getUserByLogonID("RUN_AS_USER"); // create new Subject final Subject runAsSubject = new Subject(); runAsSubject.getPrincipals().add(doAsUser); try { Object result = Subject.doAs(runAsSubject, codeToBeExecutedWithGivenUser); } catch (PrivilegedActionException pae) { // Process, wrap and rethrow exception }

NB: Here it is better not to use Administrator(could be removed from UME) user or user in the role Administrator(could be very slow). It is beeter to be the current authenticated user or a technical user.

  • Declarative - run-as in ejb-jar.xml or web.xml 

    • ejb-jar.xml

<ejb-jar>

    <assembly-descriptor>
        <security-role>
            <role-name>SOME_ROLE_NAME</role-name>
        </security-role>
    </assembly-descriptor>

    ......
      <enterprise-beans>

        <message-driven> 
        ....

          <security-identity>
                <run-as>
                     <role-name>SOME_ROLE_NAME</role-name>
                </run-as>
          </security-identity>
        </message-driven>
  </enterprise-beans>

</ejb-jar>


    • ejb-j2ee-engine.xml:

          <security-permission>
              <security-role-map>
                  <role-name>SOME_ROLE_NAME</role-name>
                  <server-role-name>APP_LOCKING_CREATE</server-role-name>
              </security-role-map>
          </security-permission>

    • Annotations in ejb class instate changes in ejb-jar.xml :

@DeclareRoles({"SOME_ROLE_NAME"})
@RunAs("SOME_ROLE_NAME")



    • web.xml:

                    <web-app>
                      <servlet>
                        <servlet-name>...</servlet-name>
                        ...
                        <run-as>
                          <role-name>MyServletRole</role-name>
                        </run-as>
                      </servlet>
                      <security-role>
                        <role-name>MyServletRole</role-name>
                      </security-role>
                    </web-app>


    • web-j2ee-engine.xml

                    <web-j2ee-engine>
                        <security-role-map>
                            <role-name>MyServletRole</role-name>
                            <server-role-name>MyASJavaRole</server-role-name>
                        </security-role-map>
                    </web-j2ee-engine>