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.mfa;
20  
21  import java.io.Serializable;
22  import java.time.ZoneId;
23  import java.time.ZonedDateTime;
24  import java.util.Date;
25  import java.util.HashSet;
26  import java.util.Optional;
27  import java.util.Set;
28  import java.util.stream.Collectors;
29  import org.apache.syncope.common.lib.wa.MfaTrustedDevice;
30  import org.apache.syncope.common.rest.api.beans.MfaTrustedDeviceQuery;
31  import org.apache.syncope.common.rest.api.service.wa.MfaTrustStorageService;
32  import org.apache.syncope.wa.bootstrap.WARestClient;
33  import org.apache.syncope.wa.starter.services.WAServiceRegistry;
34  import org.apereo.cas.configuration.model.support.mfa.trusteddevice.TrustedDevicesMultifactorProperties;
35  import org.apereo.cas.trusted.authentication.api.MultifactorAuthenticationTrustRecord;
36  import org.apereo.cas.trusted.authentication.api.MultifactorAuthenticationTrustRecordKeyGenerator;
37  import org.apereo.cas.trusted.authentication.storage.BaseMultifactorAuthenticationTrustStorage;
38  import org.apereo.cas.util.crypto.CipherExecutor;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  public class WAMultifactorAuthenticationTrustStorage extends BaseMultifactorAuthenticationTrustStorage {
43  
44      private static final Logger LOG = LoggerFactory.getLogger(WAServiceRegistry.class);
45  
46      protected static final int PAGE_SIZE = 500;
47  
48      protected final WARestClient waRestClient;
49  
50      public WAMultifactorAuthenticationTrustStorage(
51              final TrustedDevicesMultifactorProperties trustedDevicesMultifactorProperties,
52              final CipherExecutor<Serializable, String> cipherExecutor,
53              final MultifactorAuthenticationTrustRecordKeyGenerator keyGenerationStrategy,
54              final WARestClient waRestClient) {
55  
56          super(trustedDevicesMultifactorProperties, cipherExecutor, keyGenerationStrategy);
57          this.waRestClient = waRestClient;
58      }
59  
60      @Override
61      protected MultifactorAuthenticationTrustRecord saveInternal(final MultifactorAuthenticationTrustRecord record) {
62          MfaTrustedDevice device = new MfaTrustedDevice();
63          device.setRecordKey(record.getRecordKey());
64          device.setId(record.getId());
65          device.setName(record.getName());
66          device.setDeviceFingerprint(record.getDeviceFingerprint());
67          Optional.ofNullable(record.getExpirationDate()).
68                  ifPresent(date -> device.setExpirationDate(date.toInstant().atZone(ZoneId.systemDefault())));
69          device.setRecordDate(record.getRecordDate());
70  
71          LOG.trace("Saving multifactor authentication trust record [{}]", device);
72  
73          waRestClient.getService(MfaTrustStorageService.class).create(record.getPrincipal(), device);
74  
75          return record;
76      }
77  
78      @Override
79      public void remove(final ZonedDateTime expirationDate) {
80          waRestClient.getService(MfaTrustStorageService.class).delete(
81                  new MfaTrustedDeviceQuery.Builder().expirationDate(expirationDate.toOffsetDateTime()).build());
82      }
83  
84      @Override
85      public void remove(final String recordKey) {
86          waRestClient.getService(MfaTrustStorageService.class).delete(
87                  new MfaTrustedDeviceQuery.Builder().recordKey(recordKey).build());
88      }
89  
90      protected MultifactorAuthenticationTrustRecord translate(final MfaTrustedDevice device) {
91          MultifactorAuthenticationTrustRecord record = new MultifactorAuthenticationTrustRecord();
92          record.setRecordKey(device.getRecordKey());
93          record.setId(device.getId());
94          record.setName(device.getName());
95          record.setDeviceFingerprint(device.getDeviceFingerprint());
96          Optional.ofNullable(device.getExpirationDate()).
97                  ifPresent(date -> record.setExpirationDate(Date.from(date.toInstant())));
98          record.setRecordDate(device.getRecordDate());
99          return record;
100     }
101 
102     @Override
103     public Set<? extends MultifactorAuthenticationTrustRecord> getAll() {
104         if (!waRestClient.isReady()) {
105             LOG.debug("Syncope client is not yet ready to fetch MFA trusted device records");
106             return Set.of();
107         }
108 
109         int count = waRestClient.getService(MfaTrustStorageService.class).
110                 search(new MfaTrustedDeviceQuery.Builder().page(1).size(0).build()).getTotalCount();
111 
112         Set<MultifactorAuthenticationTrustRecord> result = new HashSet<>();
113 
114         for (int page = 1; page <= (count / PAGE_SIZE) + 1; page++) {
115             waRestClient.getService(MfaTrustStorageService.class).
116                     search(new MfaTrustedDeviceQuery.Builder().page(page).size(PAGE_SIZE).
117                             orderBy("expirationDate").build()).
118                     getResult().stream().
119                     map(this::translate).
120                     forEach(result::add);
121         }
122 
123         return result;
124     }
125 
126     @Override
127     public Set<? extends MultifactorAuthenticationTrustRecord> get(final ZonedDateTime onOrAfterDate) {
128         if (!waRestClient.isReady()) {
129             LOG.debug("Syncope client is not yet ready to fetch MFA trusted device records");
130             return Set.of();
131         }
132 
133         return waRestClient.getService(MfaTrustStorageService.class).
134                 search(new MfaTrustedDeviceQuery.Builder().recordDate(onOrAfterDate.toOffsetDateTime()).build()).
135                 getResult().stream().
136                 map(this::translate).
137                 collect(Collectors.toSet());
138     }
139 
140     @Override
141     public Set<? extends MultifactorAuthenticationTrustRecord> get(final String principal) {
142         if (!waRestClient.isReady()) {
143             LOG.debug("Syncope client is not yet ready to fetch MFA trusted device records");
144             return Set.of();
145         }
146 
147         return waRestClient.getService(MfaTrustStorageService.class).
148                 search(new MfaTrustedDeviceQuery.Builder().principal(principal).build()).getResult().stream().
149                 map(this::translate).
150                 collect(Collectors.toSet());
151     }
152 
153     @Override
154     public MultifactorAuthenticationTrustRecord get(final long id) {
155         if (!waRestClient.isReady()) {
156             LOG.debug("Syncope client is not yet ready to fetch MFA trusted device records");
157             return null;
158         }
159 
160         return waRestClient.getService(MfaTrustStorageService.class).
161                 search(new MfaTrustedDeviceQuery.Builder().id(id).build()).getResult().stream().findFirst().
162                 map(this::translate).
163                 orElse(null);
164     }
165 }