Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Last revision Both sides next revision
tutorial:dev:override_filter [2018/07/12 11:25]
tomiskar
tutorial:dev:override_filter [2019/02/04 09:20]
tomiskar
Line 1: Line 1:
 +====== Module - Override a filter in custom module ======
  
 +A [[devel:documentation:architecture:dev:filters|mechanism]] for dynamic registry and composing of filters has been developed in the application for searching the data in IdM (identities, roles, tree structure components, etc.). A new filter can be registered for existing REST services in any module. 
 +
 +The aim of this tutorial is show the way, how to override some actual filter behavior. We chosen **filter on identity's username**, which is represented by ''username'' parameter in search (url parameter). This filter is implemented in core module and search all identities, which have the same username as given parameter value (equals). We want to override this filter => we want to search all identities with username, which contain given parameter value (like).
 +
 +Source codes for this tutorial can be found in the [[https://github.com/bcvsolutions/CzechIdMng/blob/f1af4dc460b185c0668508ce6def223cd11e3971/Realization/backend/example/src/main/java/eu/bcvsolutions/idm/example/repository/filter/UsernameIdentityFilter.java|example module]]
 +
 +===== What do you need before you start =====
 +
 +  * You need to install CzechIdM 7.5.0 (and higher). We have CzechIdM installed for this tutorial on server ''http://localhost:8080/idm-backend''.
 +  * Create identity to call tests with ''curl'', which will have permission to read identities. We are using demo ''admin:admin'' identity.
 +  * Create test identity with username ''test12345''. This identity will be used in next step for testing.
 +
 +===== 01 Test search identity by username =====
 +
 +At start, we will search identity by username - we will see, how core filter works. Just core filter is implemented now, so command:
 +
 +   $curl -u admin:admin http://localhost:8080/idm-backend/api/v1/identities?username=test12345
 +   
 +returns our prepared test identity, but command
 +
 +   $curl -u admin:admin http://localhost:8080/idm-backend/api/v1/identities?username=test1234 
 +
 +returns nothing (if we don't have identity with username ''test1234'' created:)).
 +
 +===== 02 Filter implemetation =====
 +
 +We'll create new filter in our module, which search all identities with username, which contains given parameter value (like).
 +
 +<code java>
 +@Component("exampleUsernameIdentityFilter")
 +@Description("Filter by identity's username - search as \"like\" in username - case insensitive")
 +public class UsernameIdentityFilter extends AbstractFilterBuilder<IdmIdentity, IdmIdentityFilter> {
 +
 + @Autowired
 + public UsernameIdentityFilter(IdmIdentityRepository repository) {
 + super(repository);
 + }
 +
 + @Override
 + public String getName() {
 + return IdmIdentityFilter.PARAMETER_USERNAME;
 + }
 +
 + @Override
 + public Predicate getPredicate(Root<IdmIdentity> root, CriteriaQuery<?> query, CriteriaBuilder builder, IdmIdentityFilter filter) {
 + if (filter.getUsername() == null) {
 + return null;
 + }
 + return builder.like(builder.lower(root.get(IdmIdentity_.username)), "%" + filter.getUsername() + "%");
 + }
 +
 + @Override
 + public int getOrder() {
 + // 0 => default, we don't want to override filter as default, but is possible when order is less than 0. 
 + return 10;
 + }
 +}
 +</code>
 +
 +New filter is registered to search identities (see FilterBuilder template), when parameter ''IdmIdentityFilter.PARAMETER_USERNAME'' is given in search parameters. Filter behavior is implemented in ''getPredicate'' method. Method ''getOrder'' says, which filter will be used as default. For example, if we want to add new filter and we want to make him default without any additional configuration, then we'll return value e.g. ''-10''. Then this filter will be used, when application starts as default (=> order before core filters), respectively before all filters with order greater than ''-10''
 +
 +===== 03 Configure filter usage =====
 +
 +We added new filter with order ''10'', so default filter is still used, because all core filters has order ''0'' (**the smallest order wins** - see ''[[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/Ordered.html|@Ordered]]''). That is what we wants in the most ways. We don't want to change default behavior, but we want to be able to configure, which filter is used explicitly => choose one implementation.
 +
 +So, we can go to the application configuration page (or to application.property file) and set property value:
 +
 +<code properties>
 +idm.sec.core.filter.IdmIdentity.username.impl=exampleUsernameIdentityFilter
 +</code>
 +
 +<note important>We added new filter with order ''10'', so default filter is still used, because all core filters has order ''0'' (**the smallest order wins** - see ''[[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/Ordered.html|@Ordered]]'').</note>
 +
 +Read more about [[devel:documentation:application_configuration:dev:backend#entity_filters|filter configuration]].
 +
 +===== 04 Test search identity by username =====
 +
 +We execute test commands again:
 +  $curl -u admin:admin http://localhost:8080/idm-backend/api/v1/identities?username=test12345
 +  $curl -u admin:admin http://localhost:8080/idm-backend/api/v1/identities?username=test1234 
 +  
 +<note tip>Congratulations, both command will find your test identity, because new filter is used.</note>
 +
 +===== 05 Create test for filter =====
 +
 +<code java>
 +
 +@Transactional
 +public class UsernameIdentityFilterTest extends AbstractIntegrationTest {
 +
 + @Autowired
 + private UsernameIdentityFilter usernameIdentityFilter;
 +
 + @Test
 + public void testFilteringFound() {
 + String username = getHelper().createName();
 + IdmIdentityDto identityOne = getHelper().createIdentity(username);
 + IdmIdentityDto identityTwo = getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
 + IdmIdentityDto identityThree = getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
 +
 + IdmIdentityFilter filter = new IdmIdentityFilter();
 + filter.setUsername(username);
 + List<IdmIdentity> identities = usernameIdentityFilter.find(filter, null).getContent();
 +
 + assertEquals(3, identities.size());
 +
 + IdmIdentity identity = identities.stream().filter(ident -> ident.getId().equals(identityOne.getId())).findFirst().get();
 + assertNotNull(identity);
 +
 + identity = identities.stream().filter(ident -> ident.getId().equals(identityTwo.getId())).findFirst().get();
 + assertNotNull(identity);
 +
 + identity = identities.stream().filter(ident -> ident.getId().equals(identityThree.getId())).findFirst().get();
 + assertNotNull(identity);
 + }
 +
 + @Test
 + public void testFilteringNotFound() {
 + String username = "usernameValue" + System.currentTimeMillis();
 + getHelper().createIdentity(username);
 + getHelper().createIdentity("123" + username + getHelper().createName());
 + getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
 +
 + IdmIdentityFilter filter = new IdmIdentityFilter();
 + filter.setUsername("username1Value"); // value is different than variable username
 + List<IdmIdentity> identities = usernameIdentityFilter.find(filter, null).getContent();
 +
 + assertEquals(0, identities.size());
 + }
 +}
 +</code>
  • by kotisovam