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.util.Comparator;
23  import java.util.List;
24  import java.util.Objects;
25  import java.util.stream.Collectors;
26  import org.apache.commons.lang3.builder.CompareToBuilder;
27  import org.apache.commons.lang3.builder.EqualsBuilder;
28  import org.apache.commons.lang3.tuple.Pair;
29  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
30  import org.apache.syncope.common.lib.wa.U2FDevice;
31  import org.apache.syncope.core.logic.AbstractAuthProfileLogic;
32  import org.apache.syncope.core.persistence.api.dao.AuthProfileDAO;
33  import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
34  import org.apache.syncope.core.persistence.api.entity.EntityFactory;
35  import org.apache.syncope.core.persistence.api.entity.am.AuthProfile;
36  import org.apache.syncope.core.provisioning.api.data.AuthProfileDataBinder;
37  import org.springframework.security.access.prepost.PreAuthorize;
38  
39  public class U2FRegistrationLogic extends AbstractAuthProfileLogic {
40  
41      protected final EntityFactory entityFactory;
42  
43      public U2FRegistrationLogic(
44              final EntityFactory entityFactory,
45              final AuthProfileDAO authProfileDAO,
46              final AuthProfileDataBinder binder) {
47  
48          super(authProfileDAO, binder);
49          this.entityFactory = entityFactory;
50      }
51  
52      @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
53      public void create(final String owner, final U2FDevice device) {
54          AuthProfile profile = authProfileDAO.findByOwner(owner).orElseGet(() -> {
55              AuthProfile authProfile = entityFactory.newEntity(AuthProfile.class);
56              authProfile.setOwner(owner);
57              return authProfile;
58          });
59  
60          List<U2FDevice> devices = profile.getU2FRegisteredDevices();
61          devices.add(device);
62          profile.setU2FRegisteredDevices(devices);
63          authProfileDAO.save(profile);
64      }
65  
66      @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
67      public void delete(final Long id, final OffsetDateTime expirationDate) {
68          List<AuthProfile> profiles = authProfileDAO.findAll(-1, -1);
69          profiles.forEach(profile -> {
70              List<U2FDevice> devices = profile.getU2FRegisteredDevices();
71              if (devices != null) {
72                  if (id != null) {
73                      devices.removeIf(device -> device.getId() == id);
74                  } else if (expirationDate != null) {
75                      devices.removeIf(device -> device.getIssueDate().compareTo(expirationDate) < 0);
76                  } else {
77                      devices = List.of();
78                  }
79                  profile.setU2FRegisteredDevices(devices);
80                  authProfileDAO.save(profile);
81              }
82          });
83      }
84  
85      @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
86      public Pair<Integer, List<U2FDevice>> search(
87              final Integer page,
88              final Integer itemsPerPage,
89              final Long id,
90              final OffsetDateTime expirationDate,
91              final List<OrderByClause> orderByClauses) {
92  
93          List<Comparator<U2FDevice>> comparatorList = orderByClauses.
94                  stream().
95                  map(orderByClause -> {
96                      Comparator<U2FDevice> comparator = null;
97                      if (orderByClause.getField().equals("id")) {
98                          comparator = (o1, o2) -> new CompareToBuilder().
99                                  append(o1.getId(), o2.getId()).toComparison();
100                     }
101                     if (orderByClause.getField().equals("issueDate")) {
102                         comparator = (o1, o2) -> new CompareToBuilder().
103                                 append(o1.getIssueDate(), o2.getIssueDate()).toComparison();
104                     }
105                     if (orderByClause.getField().equals("record")) {
106                         comparator = (o1, o2) -> new CompareToBuilder().
107                                 append(o1.getRecord(), o2.getRecord()).toComparison();
108                     }
109                     if (comparator != null) {
110                         if (orderByClause.getDirection() == OrderByClause.Direction.DESC) {
111                             return comparator.reversed();
112                         }
113                         return comparator;
114                     }
115                     return null;
116                 }).
117                 filter(Objects::nonNull).
118                 collect(Collectors.toList());
119 
120         List<U2FDevice> devices = authProfileDAO.findAll(-1, -1).
121                 stream().
122                 map(AuthProfile::getU2FRegisteredDevices).
123                 filter(Objects::nonNull).
124                 flatMap(List::stream).
125                 filter(device -> {
126                     EqualsBuilder builder = new EqualsBuilder();
127                     if (id != null) {
128                         builder.append(id, (Long) device.getId());
129                     }
130                     if (expirationDate != null) {
131                         builder.appendSuper(device.getIssueDate().compareTo(expirationDate) >= 0);
132                     }
133                     return builder.build();
134                 }).
135                 filter(Objects::nonNull).
136                 collect(Collectors.toList());
137 
138         List<U2FDevice> result = devices.stream().
139                 limit(itemsPerPage).
140                 skip(itemsPerPage * (page <= 0 ? 0L : page.longValue() - 1L)).
141                 sorted((o1, o2) -> {
142                     int compare;
143                     for (Comparator<U2FDevice> comparator : comparatorList) {
144                         compare = comparator.compare(o1, o2);
145                         if (compare != 0) {
146                             return compare;
147                         }
148                     }
149                     return 0;
150                 })
151                 .collect(Collectors.toList());
152         return Pair.of(devices.size(), result);
153     }
154 }