Showing posts with label Security Architecture. Show all posts
Showing posts with label Security Architecture. Show all posts

WebService API - Security Architecture in Hybris e-commerce suit



The Security Strategies The web service security framework implements the strategy pattern, allowing the user to select from a set of security strategies that currently include:
  • Access Manager Security Strategy - based upon the hMC security paradigm
  • Property File Security Strategy - based upon configuration provided in a properties file
  • Custom Security Strategy - allowing the user to write their own strategy
User Group for Web Services
By default the Access Manager Security Strategy is adopted, which authorises a user only if they are in a new security group named webservicegroup. This is not set up by default, so be sure to create this group for your RESTful calls to be authorised as discussed below.
Each strategy implements the SecurityStrategy interface:
public interface SecurityStrategy
{
 boolean isResourceOperationAllowed(final RestResource resource, final String operation);
 boolean isResourceCommandAllowed(final RestResource resource, final String command);
 boolean isDtoOperationAllowed(final Class<?> objectClass, final String operation);
 boolean isAttributeOperationAllowed(final Class<?> attrObjectClass, final String attrQualifier, final String attrOperation);
}
However both strategies differ in implementations and intentions. To specify which strategy to adopt, modify the securityStrategy entry in the platformwebservices-web-spring.xml file:
platformwebservices-web-spring.xml
<beans>
  <!-- ... --->
  <bean id="securityStrategy"
  class="de.hybris.platform.webservices.AccessManagerSecurityStrategy"
  scope="prototype" parent="abstractSecurityStrategy"/>
 
  <!-- <bean id="securityStrategy"
  class="de.hybris.platform.webservices.PropertyFileSecurityStrategy"
  scope="prototype" parent="abstractSecurityStrategy"/>  -->
 
  <!-- <bean id="securityStrategy"
  class="de.hybris.platform.webservices.CustomSecurityStrategy" scope="prototype"
  parent="abstractSecurityStrategy"/>--->
  <!-- ... --->
 
  <bean id="abstractBaseResource"
  class="de.hybris.platform.webservices.AbstractResource" abstract="true"
  scope="prototype">
  <!-- ... --->
  <property name="securityStrategy" ref="securityStrategy"/>
  </bean>
</beans>
If you wish to disable security mechanisms for any reason, it is enough to remove securityStrategy property from the abstractBaseResource bean.
Below we consider the various strategies, starting with the default: Access Manager Security Strategy.

Access Manager Security Strategy

The Access Manager Security Strategy is the default strategy adopted by the hybris WebService API and uses the hMC Access Rights approach.
The Access Manager Security Strategy authorises a user only if they are in a security group named webservicegroup. This is not set up by default, so please be sure to create this group as discussed below, for your RESTful calls to be accepted. The name of this user group is configurable in project.properties file:
webservices.security.group=webservicegroup
By default three user groups are members of this group:
  • admingroup
  • employeegroup
  • customergroup


In RESTful communication, the mapping between the HTTP methods and CRUD operations are as follows:
HTTP method CRUD operation
GET Read
POST Create / Update
PUT Create / Update
DELETE Delete
As seen, both POST and PUT may refer to Create and Update operations. To determine which is meant, when a POST or PUT request is processed, we check if the referenced resource already exists or not. The following situations are possible:
  • If the referenced resource does not exist, it is necessary to check if the user has the right to create instances of the corresponding type.
  • Ff the referenced resource does exist, it is necessary to check if the user has the right to update instances of the corresponding type.
The central management of access rights to each type and its attributes is located within the hybris Management Console:

The type based web services security configuration, managed in hMC is divided into two basic steps:
  1. Resource (type) level security
  2. Attribute level security, which also contains the type level security
For resource level it is possible to set Read, Change, Create and Delete rights. For attribute level security, only the Read and Change rights may be set.
If a user does not have the right to a specified operation on a requested resource, the following message appears:
You do not have permission to request this resource (resource name) using HTTP_method method.
Type level security is included in attribute level security checking. If any operation is not allowed for the specified attribute type, the user receives the message:
You do not have permission to CRUD operation: DTOclassName dto.
If a user has no Read rights for a certain attribute of the requested resource, this attribute is excluded from the response. If a user tries to update an attribute, which he is not allowed to change, the attribute is not modified and the HTTP status code Forbidden (403) is sent with the message:
You do not have permission to change list_of_attributes attributes of the DTOclassName dto.
If a user has Change right to some, but not all attributes of a resource and tries to update all of them, none of them are updated. In this case the user should remove not allowed attributes from the request.
If a user requests a resource and has Read access to some, but not all attributes of the requested resource, then those unavailable attributes are not included in the XML response.

Examples


User A has all access rights.
MyLanguage resource extends Language resource.
Type Attribute Read Change Create Delete
Language  
MyLanguage  

Method URL Result
GET /languages List of all Language instances, but without MyLanguage instances.
GET /languages/de Details of de language.
GET /mylanguages/myde HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
PUT/POST /languages/de If the referenced de language exists, it is updated. Otherwise it is created.
DELETE /languages/de Delete de language.
User B has only Read right.
Type Attribute Read Change Create Delete
Language  

Method URL Result
PUT/POST /languages/de HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
DELETE /languages/de HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
User C is not allowed to update Language resource.
Type Attribute Read Change Create Delete
Language  

Method URL Result
PUT/POST /languages/de If the referenced language does no exist, it is created.
If the referenced language exists, the request results in HTTP status code Forbidden (403), informing that the user does not have sufficient rights to execute update operation.
User D has no rights for Language resource.
Type Attribute Read Change Create Delete
Language  

Method URL Result
GET /languages Empty list, as user D has no Read access to language instances.
GET /languages/de HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
PUT/POST /languages/de HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
DELETE /languages/de HTTP status code Forbidden (403) informing that the user does not have sufficient rights to execute the requested operation.
User A has all rights.
Type Attribute Read Change Create Delete
Language  
  isocode    
  name    

Method URL Result
GET /languages/de
<language>
  <isocode>de</isocode>
   <name>German</name>
</language>
User B has no rights to read or update the name attribute.
Type Attribute Read Change Create Delete
Language  
  isocode    
  name    

Method URL Result
PUT /languages/de Body of the request:
<language>
   <isocode>de</isocode>
</language>
PUT /languages/fr Body of the request:
<language>
   <isocode>fr</isocode>
   <name>French</name>
</language>

Results in HTTP status code Forbidden (403) informing that the user has no rights to change the name attribute.

Property File Security Strategy

This strategy is based on the configuration project.properties file in the platformwebservices extension. It is a resource level security strategy.

Security Access Roles

Secured resources are given by:
  1. key, which addresses single classes or whole packages, similar to log4j
  2. value, which is a group or role followed by a list of allowed HTTP methods
Leave value of this property empty or set one or more groups.
Examples:
  • Global options. The following settings allow specified groups access to all resources, however anonymous group may just Read them:
    restjersey.security.de=admingroup[GET,PUT,DELETE,POST]
    restjersey.security.de.hybris.platform.restjersey.resources=anonymous[GET]
  • The following settings assign groups to specified resources:
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    anonymous[GET]; customergroup[GET]
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    anonymous[GET]; customergroup[GET]

Examples of Different Configurations

All use cases for admingroup are presented in the simple example. Results are retrieved using GET method.
Below different available configurations are presented:
  • restjersey.security.de.hybris.platform.restjersey.resources=
    admingroup[GET,PUT,DELETE,POST]
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    or
    restjersey.security.de.hybris.platform.restjersey.resources=
    admingroup[GET,PUT,DELETE,POST]
    or
    restjersey.security.de.hybris.platform.restjersey.resources=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    admingroup[GET,PUT,DELETE,POST]
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    admingroup[GET,PUT,DELETE,POST]
    or
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    admingroup[GET,PUT,DELETE,POST]
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    admingroup[GET,PUT,DELETE,POST]
Request Response
http://localhost:9001/ws410/rest/catalogs/ Retrieves all catalogs
http://localhost:9001/ws410/rest/catalogs/hwcatalog/ Retrieve the specified catalog.
  • restjersey.security.de.hybris.platform.restjersey.resources=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    admingroup[GET,PUT,DELETE,POST]
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    employeegroup[GET]
Request Response
http://localhost:9001/ws410/rest/catalogs/ Retrieves all catalogs
http://localhost:9001/ws410/rest/catalogs/hwcatalog/ HTTP status FORBIDDEN with the message:
You do not have permission to request this resource (CatalogResource) using GET method..
  • restjersey.security.de.hybris.platform.restjersey.resources=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    admingroup[GET,PUT,DELETE,POST]
    or
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    admingroup[GET,PUT,DELETE,POST]
Request Response
http://localhost:9001/ws410/rest/catalogs/ HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/ Retrieve the specified catalog.
  • restjersey.security.de.hybris.platform.restjersey.resources=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
    restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
    or any properties.
Request Response
http://localhost:9001/ws410/rest/catalogs/ HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/ HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.

Custom Security Strategy

It is possible for users to create their own security strategies by:
  • Implementing the SecurityStrategy interface:
public interface SecurityStrategy
{
   boolean isResourceOperationAllowed(final RestResource resource, final String operation);
   boolean isResourceCommandAllowed(final RestResource resource, final String command);
   boolean isDtoOperationAllowed(final Class<?> objectClass, final String operation);
    boolean isAttributeOperationAllowed(final Class<?> attrObjectClass, final String attrQualifier, final String attrOperation);
}
  • Registering the bean in platformwebservices-web-spring.xml:
platformwebservices-web-spring.xml
<beans>
   <!-- ... --->
   <bean id="securityStrategy" class="de.hybris.platform.webservices.CustomSecurityStrategy" scope="prototype" parent="abstractSecurityStrategy"/>
   <!-- ... --->
</beans>

Security Specific Web Services Resources


Checking credentials:

A request for a validation of the provided credentials:
http://localhost:9001/ws410/rest/login If the login process is:
  • Valid: Status is 200 OK
  • Invalid: Status is 401 Unauthorized

Lost Password Scenario

If the restjersey.security property is set to enabled, only RetrievePasswordResource is available for users who lost their passwords.
They have to access to http://localhost:9001/ws410/rest/retrievepassword resource without using basic authentication.
For example, editor user forgets his password. He uses GET method and the following URL path: http://localhost:9001/ws410/rest/retrievepassword/editor. If the user does not have access to PasswordQuestion and AnswerQuestion it is not possible to retrieve password. In other cases, user can retrieve password.
The GET method returns response with PasswordQuestion.
Now, user uses PUT method and the same URL path:
http://localhost:9001/ws410/rest/retrievepassword/editor He places PasswordAnswer within body request and executes request.
    <passwordAnswer>YOUR ANSWER</passwordAnswer>
</user>
If the PasswordAnswer is correct, user retrieves a new password in raw format. In database the password is encoded into a md5 hash.

Change Password Scenario

Use http://localhost:9001/ws410/rest/changepassword, PUT method and the following HTTP body:
<changepassword>
   <newpassword>NO EMPTY</newpassword>
</changepassword>
If you log in correctly, the new password is set.

Security Architecture Configuration

The following configuration files:
  • web.xml
  • platformwebservices-web-spring.xml
are located within the platformwebservices extension and are used to specify and wire up the security framework.

Configuration of web.xml File

web.xml
<web-app>
 <!-- ... -->
 
 <filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>
 
 <filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 
 <!-- ... -->
</web-app>
This provides a hook into the Spring Security web infrastructure. DelegatingFilterProxy is a Spring Framework class which delegates to a filter implementation which is defined as a Spring bean in an application context. In this case, the bean is named springSecurityFilterChain, which is an internal infrastructure bean created by the namespace to handle web security. Note that you should not use this bean name yourself.
The next step is configuring the application context file.

Configuration of Spring File


Web security services are configured using security elements.
platformwebservices-web-spring.xml
    <!-- ... -->
 
    <security:http>
        <security:intercept-url  pattern="/**" />
        <security:http-basic />
        <security:logout />
        <security:remember-me />
    </security:http>
 
    <security:authentication-manager  alias="mainAuthenticationManager">
      <security:authentication-provider user-service-ref="userDetailsService">
        <security:password-encoder ref="hybrisPasswordValidator">
            <!-- SaltedMD5PasswordEncoder is used -->
            <!-- <security:salt-source user-property="whatever"/> -->
        </security:password-encoder>
      </security:authentication-provider>
    </security:authentication-manager>
 
    <bean id="userDetailsService"
    class="de.hybris.platform.webservices.security.impl.HybrisUserDetailsService"
    scope="prototype">
        <property name="userService" ref="userService"/>
        <property name="modelService" ref="modelService"/>
        <property name="encryptionInfo" ref="encryptionInfo"/>
    </bean>
 
    <bean id="hybrisPasswordValidator"
    class="de.hybris.platform.webservices.security.impl.HybrisPasswordValidator">
        <property name="encryptionInfo" ref="encryptionInfo"/>
    </bean>
 
    <bean id="encryptionInfo"
    class="de.hybris.platform.webservices.security.impl.EncryptionInfo"/>
 
    <!-- ... -->
</beans>
  • http configuration:
    This element enables web security and denotes that all URLs within our web services should be secured. The WebService API uses basic authentication which is used to prompt for a login when a user attempts to access a protected resource.
  • authentication-provider and password-encoder:
    The hybris web services framework authenticates users against hMC members. We have own implementation of Spring Security UserDetailsService, within which by currently authenticated username it passes the user password and granted authorities (hmc usergroups) to the password validation procedure. Some users have encrypted password (Salted MD5) and others not. Therefore we provide the hybrisPasswordValidator, which takes appropriate care of password comparison.