1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.wa.starter.webauthn;
20
21 import com.fasterxml.jackson.core.type.TypeReference;
22 import com.yubico.data.CredentialRegistration;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.stream.Collectors;
26 import java.util.stream.Stream;
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.WebAuthnAccount;
30 import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential;
31 import org.apache.syncope.common.rest.api.service.wa.WebAuthnRegistrationService;
32 import org.apache.syncope.wa.bootstrap.WARestClient;
33 import org.apereo.cas.configuration.CasConfigurationProperties;
34 import org.apereo.cas.util.crypto.CipherExecutor;
35 import org.apereo.cas.webauthn.WebAuthnUtils;
36 import org.apereo.cas.webauthn.storage.BaseWebAuthnCredentialRepository;
37 import org.jooq.lambda.Unchecked;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class WAWebAuthnCredentialRepository extends BaseWebAuthnCredentialRepository {
42
43 protected static final Logger LOG = LoggerFactory.getLogger(WAWebAuthnCredentialRepository.class);
44
45 protected final WARestClient waRestClient;
46
47 public WAWebAuthnCredentialRepository(final CasConfigurationProperties properties,
48 final WARestClient waRestClient) {
49 super(properties, CipherExecutor.noOpOfStringToString());
50 this.waRestClient = waRestClient;
51 }
52
53 protected WebAuthnRegistrationService service() {
54 return waRestClient.getService(WebAuthnRegistrationService.class);
55 }
56
57 @Override
58 public boolean removeRegistrationByUsername(
59 final String username,
60 final CredentialRegistration credentialRegistration) {
61
62 String id = credentialRegistration.getCredential().getCredentialId().getHex();
63 service().delete(username, id);
64 return true;
65 }
66
67 @Override
68 public boolean removeAllRegistrations(final String username) {
69 service().delete(username);
70 return true;
71 }
72
73 @Override
74 public Stream<? extends CredentialRegistration> stream() {
75 return service().list().
76 stream().
77 map(WebAuthnAccount::getCredentials).
78 flatMap(Collection::stream).
79 map(Unchecked.function(record -> {
80 String json = getCipherExecutor().decode(record.getJson());
81 return WebAuthnUtils.getObjectMapper().readValue(json, new TypeReference<>() {
82 });
83 }));
84 }
85
86 @Override
87 protected void update(final String username, final Collection<CredentialRegistration> records) {
88 try {
89 List<WebAuthnDeviceCredential> credentials = records.stream().
90 map(Unchecked.function(record -> {
91 String json = getCipherExecutor().encode(WebAuthnUtils.getObjectMapper().
92 writeValueAsString(record));
93 return new WebAuthnDeviceCredential.Builder().
94 json(json).
95 identifier(record.getCredential().getCredentialId().getHex()).
96 build();
97 })).
98 collect(Collectors.toList());
99
100 WebAuthnAccount account = service().read(username);
101 if (account != null) {
102 account.getCredentials().addAll(credentials);
103 service().update(username, account);
104 } else {
105 account = new WebAuthnAccount.Builder().credentials(credentials).build();
106 service().create(username, account);
107 }
108 } catch (final Exception e) {
109 LOG.error(e.getMessage(), e);
110 }
111 }
112
113 @Override
114 public Collection<CredentialRegistration> getRegistrationsByUsername(final String username) {
115 try {
116 return service().read(username).getCredentials().stream().
117 map(Unchecked.function(record -> {
118 String json = getCipherExecutor().decode(record.getJson());
119 return WebAuthnUtils.getObjectMapper()
120 .readValue(json, new TypeReference<CredentialRegistration>() {
121 });
122 })).
123 collect(Collectors.toList());
124 } catch (SyncopeClientException e) {
125 if (e.getType() == ClientExceptionType.NotFound) {
126 LOG.info("Could not locate account for {}", username);
127 } else {
128 LOG.error(e.getMessage(), e);
129 }
130 } catch (Exception e) {
131 LOG.error(e.getMessage(), e);
132 }
133 return List.of();
134 }
135 }