View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.logic.wa;
20  
21  import java.time.OffsetDateTime;
22  import java.time.ZonedDateTime;
23  import java.util.Comparator;
24  import java.util.List;
25  import java.util.Objects;
26  import java.util.stream.Collectors;
27  import java.util.stream.Stream;
28  import org.apache.commons.lang3.builder.CompareToBuilder;
29  import org.apache.commons.lang3.builder.EqualsBuilder;
30  import org.apache.commons.lang3.tuple.Pair;
31  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
32  import org.apache.syncope.common.lib.wa.MfaTrustedDevice;
33  import org.apache.syncope.core.logic.AbstractAuthProfileLogic;
34  import org.apache.syncope.core.persistence.api.dao.AuthProfileDAO;
35  import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
36  import org.apache.syncope.core.persistence.api.entity.EntityFactory;
37  import org.apache.syncope.core.persistence.api.entity.am.AuthProfile;
38  import org.apache.syncope.core.provisioning.api.data.AuthProfileDataBinder;
39  import org.springframework.security.access.prepost.PreAuthorize;
40  
41  public class MfaTrusStorageLogic extends AbstractAuthProfileLogic {
42  
43      protected final EntityFactory entityFactory;
44  
45      public MfaTrusStorageLogic(
46              final EntityFactory entityFactory,
47              final AuthProfileDAO authProfileDAO,
48              final AuthProfileDataBinder binder) {
49  
50          super(authProfileDAO, binder);
51          this.entityFactory = entityFactory;
52      }
53  
54      @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
55      public Pair<Integer, List<MfaTrustedDevice>> search(
56              final Integer page,
57              final Integer itemsPerPage,
58              final String principal,
59              final Long id,
60              final OffsetDateTime recordDate,
61              final List<OrderByClause> orderByClauses) {
62  
63          List<Comparator<MfaTrustedDevice>> comparatorList = orderByClauses.
64                  stream().
65                  map(orderByClause -> {
66                      Comparator<MfaTrustedDevice> comparator = null;
67                      if (orderByClause.getField().equals("id")) {
68                          comparator = (o1, o2) -> new CompareToBuilder().
69                                  append(o1.getId(), o2.getId()).toComparison();
70                      }
71                      if (orderByClause.getField().equals("expirationDate")) {
72                          comparator = (o1, o2) -> new CompareToBuilder().
73                                  append(o1.getExpirationDate(), o2.getExpirationDate()).toComparison();
74                      }
75                      if (orderByClause.getField().equals("recordDate")) {
76                          comparator = (o1, o2) -> new CompareToBuilder().
77                                  append(o1.getRecordDate(), o2.getRecordDate()).toComparison();
78                      }
79                      if (comparator != null) {
80                          if (orderByClause.getDirection() == OrderByClause.Direction.DESC) {
81                              return comparator.reversed();
82                          }
83                          return comparator;
84                      }
85                      return null;
86                  }).
87                  filter(Objects::nonNull).
88                  collect(Collectors.toList());
89  
90          List<MfaTrustedDevice> devices = (principal == null
91                  ? authProfileDAO.findAll(-1, -1).stream().
92                          map(AuthProfile::getMfaTrustedDevices).filter(Objects::nonNull).flatMap(List::stream)
93                  : authProfileDAO.findByOwner(principal).
94                          map(AuthProfile::getMfaTrustedDevices).filter(Objects::nonNull).map(List::stream).
95                          orElse(Stream.empty())).
96                  filter(device -> {
97                      EqualsBuilder builder = new EqualsBuilder();
98                      builder.appendSuper(device.getExpirationDate().isAfter(ZonedDateTime.now()));
99                      if (id != null) {
100                         builder.append(id, (Long) device.getId());
101                     }
102                     if (recordDate != null) {
103                         builder.appendSuper(device.getRecordDate().isAfter(recordDate.toZonedDateTime()));
104                     }
105                     return builder.build();
106                 }).
107                 filter(Objects::nonNull).
108                 collect(Collectors.toList());
109 
110         List<MfaTrustedDevice> result = devices.stream().
111                 limit(itemsPerPage).
112                 skip(itemsPerPage * (page <= 0 ? 0L : page.longValue() - 1L)).
113                 sorted((o1, o2) -> {
114                     int compare;
115                     for (Comparator<MfaTrustedDevice> comparator : comparatorList) {
116                         compare = comparator.compare(o1, o2);
117                         if (compare != 0) {
118                             return compare;
119                         }
120                     }
121                     return 0;
122                 })
123                 .collect(Collectors.toList());
124         return Pair.of(devices.size(), result);
125     }
126 
127     @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
128     public void create(final String owner, final MfaTrustedDevice device) {
129         AuthProfile profile = authProfileDAO.findByOwner(owner).orElseGet(() -> {
130             AuthProfile authProfile = entityFactory.newEntity(AuthProfile.class);
131             authProfile.setOwner(owner);
132             return authProfile;
133         });
134 
135         List<MfaTrustedDevice> devices = profile.getMfaTrustedDevices();
136         devices.add(device);
137         profile.setMfaTrustedDevices(devices);
138         authProfileDAO.save(profile);
139     }
140 
141     @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
142     public void delete(final OffsetDateTime expirationDate, final String recordKey) {
143         List<AuthProfile> profiles = authProfileDAO.findAll(-1, -1);
144         profiles.forEach(profile -> {
145             List<MfaTrustedDevice> devices = profile.getMfaTrustedDevices();
146             if (devices != null) {
147                 if (recordKey != null) {
148                     devices.removeIf(device -> recordKey.equals(device.getRecordKey()));
149                 } else if (expirationDate != null) {
150                     devices.removeIf(device -> device.getExpirationDate().isBefore(expirationDate.toZonedDateTime()));
151                 } else {
152                     devices = List.of();
153                 }
154                 profile.setMfaTrustedDevices(devices);
155                 authProfileDAO.save(profile);
156             }
157         });
158     }
159 }