View Javadoc
1   /*
2    * Copyright (c) 2002-2024, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.identitystore.modules.taskstack.provider;
35  
36  import fr.paris.lutece.plugins.identitystore.business.attribute.AttributeKey;
37  import fr.paris.lutece.plugins.identitystore.business.identity.Identity;
38  import fr.paris.lutece.plugins.identitystore.business.identity.IdentityHome;
39  import fr.paris.lutece.plugins.identitystore.business.referentiel.RefAttributeCertificationLevel;
40  import fr.paris.lutece.plugins.identitystore.service.attribute.IdentityAttributeService;
41  import fr.paris.lutece.plugins.identitystore.service.attribute.IdentityAttributeValidationService;
42  import fr.paris.lutece.plugins.identitystore.service.contract.AttributeCertificationDefinitionService;
43  import fr.paris.lutece.plugins.identitystore.service.identity.IdentityAttributeNotFoundException;
44  import fr.paris.lutece.plugins.identitystore.v3.web.rs.DtoConverter;
45  import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.common.AttributeDto;
46  import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.common.IdentityDto;
47  import fr.paris.lutece.plugins.identitystore.v3.web.rs.util.Constants;
48  import fr.paris.lutece.plugins.taskstack.exception.TaskValidationException;
49  import fr.paris.lutece.plugins.taskstack.service.ITaskManagement;
50  import fr.paris.lutece.portal.service.util.AppPropertiesService;
51  
52  import java.util.ArrayList;
53  import java.util.List;
54  import java.util.stream.Collectors;
55  
56  public abstract class AbstractTaskManagement implements ITaskManagement
57  {
58      protected IdentityDto validateAndGetIdentity( final String cuid ) throws TaskValidationException
59      {
60          final Identity identity = IdentityHome.findByCustomerId( cuid );
61          if ( identity == null )
62          {
63              throw new TaskValidationException( "No identity was found for the provided CUID" );
64          }
65          if ( identity.isDeleted( ) )
66          {
67              throw new TaskValidationException( "The identity is deleted" );
68          }
69          if ( identity.isMerged( ) )
70          {
71              throw new TaskValidationException( "The identity is merged" );
72          }
73  
74          return DtoConverter.convertIdentityToDto( identity );
75      }
76  
77      protected void validateEmail( final IdentityDto identityDto, final boolean checkCertification ) throws TaskValidationException
78      {
79          final AttributeDto emailAttr = identityDto.getAttributes( ).stream( ).filter( a -> a.getKey( ).equals( Constants.PARAM_EMAIL ) ).findFirst( )
80                  .orElseThrow( ( ) -> new TaskValidationException( "The identity does not have an email attribute" ) );
81          try
82          {
83              if ( !IdentityAttributeValidationService.instance( ).validateAttribute( Constants.PARAM_EMAIL, emailAttr.getValue( ) ) )
84              {
85                  throw new TaskValidationException( "The identity email has an invalid value format" );
86              }
87          }
88          catch( final IdentityAttributeNotFoundException e )
89          {
90              throw new TaskValidationException( e.getMessage( ), e );
91          }
92          if ( checkCertification )
93          {
94              if ( emailAttr.getCertificationLevel( ) != null && emailAttr.getCertificationLevel( ) > 100 )
95              {
96                  throw new TaskValidationException( "The identity email has already been validated" );
97              }
98          }
99      }
100 
101     protected void validateAccountRequirement( final IdentityDto identityDto ) throws TaskValidationException
102     {
103         this.validateEmail( identityDto, false );
104         if ( identityDto.isMonParisActive( ) )
105         {
106             throw new TaskValidationException( "The identity is already connected" );
107         }
108         this.validateIdentityCertification( identityDto );
109     }
110 
111     // TODO valider la spec: l'identité doit avoir un niveau minimum de certification (à définir en properties, le niveau de ORIG1 pour commencer)
112     private void validateIdentityCertification( final IdentityDto identityDto ) throws TaskValidationException
113     {
114         final String minCertificationCode = AppPropertiesService.getProperty( "task.account.creation.minimum.certification" );
115         final List<String> pivotKeys = IdentityAttributeService.instance( ).getPivotAttributeKeys( ).stream( ).map( AttributeKey::getKeyName )
116                 .collect( Collectors.toList( ) );
117         final List<AttributeDto> pivotAttributes = identityDto.getAttributes( ).stream( ).filter( a -> pivotKeys.contains( a.getKey( ) ) )
118                 .collect( Collectors.toList( ) );
119 
120         // Born in France
121         if ( pivotAttributes.size( ) == pivotKeys.size( ) )
122         {
123             this.validateAttributesCertification( pivotAttributes, minCertificationCode );
124         }
125 
126         // Not born in france
127         else
128             if ( pivotAttributes.size( ) == pivotKeys.size( ) - 1
129                     && pivotAttributes.stream( ).map( AttributeDto::getKey ).noneMatch( s -> s.equals( Constants.PARAM_BIRTH_PLACE_CODE ) )
130                     && pivotAttributes.stream( ).anyMatch( attributeDto -> attributeDto.getKey( ).equals( Constants.PARAM_BIRTH_COUNTRY_CODE )
131                             && !attributeDto.getValue( ).equals( "99100" ) ) )
132             {
133                 this.validateAttributesCertification( pivotAttributes, minCertificationCode );
134             }
135 
136             // invalid
137             else
138             {
139                 throw new TaskValidationException( "The identity has missing pivot attributes and cannot be connected" );
140             }
141     }
142 
143     private void validateAttributesCertification( final List<AttributeDto> pivotAttributes, final String minCertificationCode ) throws TaskValidationException
144     {
145         final List<String> errors = new ArrayList<>( );
146         for ( final AttributeDto attributeDto : pivotAttributes )
147         {
148             final RefAttributeCertificationLevel certificationLevel = AttributeCertificationDefinitionService.instance( ).get( minCertificationCode,
149                     attributeDto.getKey( ) );
150             final Integer minRequiredLevel = Integer.valueOf( certificationLevel.getRefCertificationLevel( ).getLevel( ) );
151             if ( attributeDto.getCertificationLevel( ) < minRequiredLevel )
152             {
153                 errors.add( "[attribute-key=" + attributeDto.getKey( ) + "][attribute-certification-level=" + attributeDto.getCertificationLevel( )
154                         + "][expected-level=" + minRequiredLevel + "]" );
155             }
156         }
157         if ( !errors.isEmpty( ) )
158         {
159             final StringBuilder error = new StringBuilder( "Some errors occurred during pivot attributes validation. The minimum certification processus is " )
160                     .append( minCertificationCode ).append( "." );
161             errors.forEach( error::append );
162             throw new TaskValidationException( error.toString( ) );
163         }
164     }
165 
166 }