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.wa.starter.u2f;
20  
21  import com.github.benmanes.caffeine.cache.LoadingCache;
22  import java.time.OffsetDateTime;
23  import java.time.ZoneId;
24  import java.util.Collection;
25  import java.util.Objects;
26  import java.util.stream.Collectors;
27  import org.apache.syncope.common.lib.SyncopeClientException;
28  import org.apache.syncope.common.lib.types.ClientExceptionType;
29  import org.apache.syncope.common.lib.wa.U2FDevice;
30  import org.apache.syncope.common.rest.api.beans.U2FDeviceQuery;
31  import org.apache.syncope.common.rest.api.service.wa.U2FRegistrationService;
32  import org.apache.syncope.wa.bootstrap.WARestClient;
33  import org.apereo.cas.adaptors.u2f.storage.BaseU2FDeviceRepository;
34  import org.apereo.cas.adaptors.u2f.storage.U2FDeviceRegistration;
35  import org.apereo.cas.configuration.CasConfigurationProperties;
36  import org.apereo.cas.util.crypto.CipherExecutor;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.springframework.util.CollectionUtils;
40  
41  public class WAU2FDeviceRepository extends BaseU2FDeviceRepository {
42  
43      private static final Logger LOG = LoggerFactory.getLogger(WAU2FDeviceRepository.class);
44  
45      protected static U2FDeviceRegistration parseRegistrationRecord(final String owner, final U2FDevice device) {
46          try {
47              return U2FDeviceRegistration.builder().
48                      id(device.getId()).
49                      username(owner).
50                      record(device.getRecord()).
51                      createdDate(device.getIssueDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).
52                      build();
53          } catch (Exception e) {
54              LOG.error(e.getMessage(), e);
55          }
56          return null;
57      }
58  
59      protected final WARestClient waRestClient;
60  
61      protected final OffsetDateTime expirationDate;
62  
63      public WAU2FDeviceRepository(
64              final CasConfigurationProperties casProperties,
65              final LoadingCache<String, String> requestStorage,
66              final WARestClient waRestClient,
67              final OffsetDateTime expirationDate) {
68  
69          super(casProperties, requestStorage, CipherExecutor.noOpOfSerializableToString());
70          this.waRestClient = waRestClient;
71          this.expirationDate = expirationDate;
72      }
73  
74      protected U2FRegistrationService service() {
75          return waRestClient.getService(U2FRegistrationService.class);
76      }
77  
78      @Override
79      public Collection<? extends U2FDeviceRegistration> getRegisteredDevices(final String owner) {
80          return service().
81                  search(new U2FDeviceQuery.Builder().owner(owner).expirationDate(expirationDate).build()).getResult().
82                  stream().
83                  map(device -> parseRegistrationRecord(owner, device)).
84                  filter(Objects::nonNull).
85                  collect(Collectors.toList());
86      }
87  
88      @Override
89      public Collection<? extends U2FDeviceRegistration> getRegisteredDevices() {
90          return service().search(new U2FDeviceQuery.Builder().expirationDate(expirationDate).build()).getResult().
91                  stream().
92                  map(device -> parseRegistrationRecord("", device)).
93                  filter(Objects::nonNull).
94                  collect(Collectors.toList());
95      }
96  
97      @Override
98      public U2FDeviceRegistration registerDevice(final U2FDeviceRegistration registration) {
99          U2FDevice record = new U2FDevice.Builder().
100                 issueDate(OffsetDateTime.of(
101                         registration.getCreatedDate().atStartOfDay(), OffsetDateTime.now().getOffset())).
102                 record(registration.getRecord()).
103                 id(registration.getId()).
104                 build();
105         service().create(registration.getUsername(), record);
106         return parseRegistrationRecord(registration.getUsername(), record);
107     }
108 
109     @Override
110     public void deleteRegisteredDevice(final U2FDeviceRegistration registration) {
111         service().delete(new U2FDeviceQuery.Builder().id(registration.getId()).build());
112     }
113 
114     @Override
115     public boolean isDeviceRegisteredFor(final String owner) {
116         try {
117             Collection<? extends U2FDeviceRegistration> devices = getRegisteredDevices(owner);
118             return !CollectionUtils.isEmpty(devices);
119         } catch (final SyncopeClientException e) {
120             if (e.getType() == ClientExceptionType.NotFound) {
121                 LOG.info("Could not locate account for owner {}", owner);
122             } else {
123                 LOG.error(e.getMessage(), e);
124             }
125         }
126         return false;
127     }
128 
129     @Override
130     public void clean() {
131         service().delete(new U2FDeviceQuery.Builder().expirationDate(expirationDate).build());
132     }
133 
134     @Override
135     public void removeAll() {
136         service().delete(new U2FDeviceQuery.Builder().build());
137     }
138 }