PublicKeyCredentialRequestOptions.java

1
// Copyright (c) 2018, Yubico AB
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are met:
6
//
7
// 1. Redistributions of source code must retain the above copyright notice, this
8
//    list of conditions and the following disclaimer.
9
//
10
// 2. Redistributions in binary form must reproduce the above copyright notice,
11
//    this list of conditions and the following disclaimer in the documentation
12
//    and/or other materials provided with the distribution.
13
//
14
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25
package com.yubico.webauthn.data;
26
27
import com.fasterxml.jackson.annotation.JsonCreator;
28
import com.fasterxml.jackson.annotation.JsonProperty;
29
import com.fasterxml.jackson.core.JsonProcessingException;
30
import com.fasterxml.jackson.databind.ObjectMapper;
31
import com.fasterxml.jackson.databind.node.ObjectNode;
32
import com.yubico.internal.util.CollectionUtil;
33
import com.yubico.internal.util.JacksonCodecs;
34
import java.util.List;
35
import java.util.Optional;
36
import lombok.Builder;
37
import lombok.NonNull;
38
import lombok.Value;
39
40
/**
41
 * The PublicKeyCredentialRequestOptions dictionary supplies get() with the data it needs to
42
 * generate an assertion.
43
 *
44
 * <p>Its `challenge` member must be present, while its other members are optional.
45
 *
46
 * @see <a
47
 *     href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dictdef-publickeycredentialrequestoptions">§5.5.
48
 *     Options for Assertion Generation (dictionary PublicKeyCredentialRequestOptions) </a>
49
 */
50
@Value
51
@Builder(toBuilder = true)
52
public class PublicKeyCredentialRequestOptions {
53
54
  /**
55
   * A challenge that the selected authenticator signs, along with other data, when producing an
56
   * authentication assertion. See the <a
57
   * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-cryptographic-challenges">§13.1
58
   * Cryptographic Challenges</a> security consideration.
59
   */
60
  @NonNull private final ByteArray challenge;
61
62
  /**
63
   * Specifies a time, in milliseconds, that the caller is willing to wait for the call to complete.
64
   *
65
   * <p>This is treated as a hint, and MAY be overridden by the client.
66
   */
67
  private final Long timeout;
68
69
  /**
70
   * Specifies the relying party identifier claimed by the caller.
71
   *
72
   * <p>If omitted, its value will be set by the client.
73
   */
74
  private final String rpId;
75
76
  /**
77
   * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials
78
   * acceptable to the caller, in descending order of the caller’s preference (the first item in the
79
   * list is the most preferred credential, and so on down the list).
80
   */
81
  private final List<PublicKeyCredentialDescriptor> allowCredentials;
82
83
  /**
84
   * Describes the Relying Party's requirements regarding <a
85
   * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#user-verification">user
86
   * verification</a> for the <code>navigator.credentials.get()</code> operation.
87
   *
88
   * <p>Eligible authenticators are filtered to only those capable of satisfying this requirement.
89
   *
90
   * <p>By default, this is not set. When not set, the default in the browser is {@link
91
   * UserVerificationRequirement#PREFERRED}.
92
   *
93
   * @see UserVerificationRequirement
94
   * @see <a
95
   *     href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#enum-userVerificationRequirement">§5.8.6.
96
   *     User Verification Requirement Enumeration (enum UserVerificationRequirement)</a>
97
   * @see <a href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#user-verification">User
98
   *     Verification</a>
99
   */
100
  private final UserVerificationRequirement userVerification;
101
102
  /**
103
   * Additional parameters requesting additional processing by the client and authenticator.
104
   *
105
   * <p>For example, if transaction confirmation is sought from the user, then the prompt string
106
   * might be included as an extension.
107
   */
108
  @NonNull @Builder.Default
109
  private final AssertionExtensionInputs extensions = AssertionExtensionInputs.builder().build();
110
111
  @JsonCreator
112
  private PublicKeyCredentialRequestOptions(
113 1 1. <init> : negated conditional → KILLED
      @NonNull @JsonProperty("challenge") ByteArray challenge,
114
      @JsonProperty("timeout") Long timeout,
115
      @JsonProperty("rpId") String rpId,
116
      @JsonProperty("allowCredentials") List<PublicKeyCredentialDescriptor> allowCredentials,
117
      @JsonProperty("userVerification") UserVerificationRequirement userVerification,
118 1 1. <init> : negated conditional → KILLED
      @NonNull @JsonProperty("extensions") AssertionExtensionInputs extensions) {
119
    this.challenge = challenge;
120
    this.timeout = timeout;
121
    this.rpId = rpId;
122
    this.allowCredentials =
123 1 1. <init> : negated conditional → KILLED
        allowCredentials == null ? null : CollectionUtil.immutableList(allowCredentials);
124
    this.userVerification = userVerification;
125
    this.extensions = extensions;
126
  }
127
128
  public Optional<Long> getTimeout() {
129 1 1. getTimeout : replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getTimeout → KILLED
    return Optional.ofNullable(timeout);
130
  }
131
132
  public Optional<List<PublicKeyCredentialDescriptor>> getAllowCredentials() {
133 1 1. getAllowCredentials : replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getAllowCredentials → KILLED
    return Optional.ofNullable(allowCredentials);
134
  }
135
136
  public Optional<UserVerificationRequirement> getUserVerification() {
137 1 1. getUserVerification : replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getUserVerification → KILLED
    return Optional.ofNullable(userVerification);
138
  }
139
140
  /**
141
   * Serialize this {@link PublicKeyCredentialRequestOptions} value to JSON suitable for sending to
142
   * the client.
143
   *
144
   * <p>Any {@link ByteArray} values in this data structure will be {@link ByteArray#getBase64Url()
145
   * Base64Url} encoded. Those values MUST be decoded into <code>BufferSource</code> values (such as
146
   * <code>Uint8Array</code>) on the client side before calling <code>navigator.credentials.get()
147
   * </code>.
148
   *
149
   * <p>After decoding binary values, the resulting JavaScript object is suitable for passing as an
150
   * argument to <code>navigator.credentials.get()</code>.
151
   *
152
   * @return a JSON value suitable for sending to the client and passing as an argument to <code>
153
   *     navigator.credentials.get()</code>, after decoding binary options from Base64Url strings.
154
   * @throws JsonProcessingException if JSON serialization fails.
155
   */
156
  public String toCredentialsGetJson() throws JsonProcessingException {
157
    ObjectMapper json = JacksonCodecs.json();
158
    ObjectNode result = json.createObjectNode();
159
    result.set("publicKey", json.valueToTree(this));
160 1 1. toCredentialsGetJson : replaced return value with "" for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::toCredentialsGetJson → KILLED
    return json.writeValueAsString(result);
161
  }
162
163
  public static PublicKeyCredentialRequestOptionsBuilder.MandatoryStages builder() {
164 1 1. builder : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::builder → KILLED
    return new PublicKeyCredentialRequestOptionsBuilder.MandatoryStages();
165
  }
166
167
  public static class PublicKeyCredentialRequestOptionsBuilder {
168
    private Long timeout = null;
169
    private String rpId = null;
170
    private List<PublicKeyCredentialDescriptor> allowCredentials = null;
171
172
    public static class MandatoryStages {
173
      private final PublicKeyCredentialRequestOptionsBuilder builder =
174
          new PublicKeyCredentialRequestOptionsBuilder();
175
176
      /**
177
       * {@link PublicKeyCredentialRequestOptionsBuilder#challenge(ByteArray) challenge} is a
178
       * required parameter.
179
       *
180
       * @see PublicKeyCredentialRequestOptionsBuilder#challenge(ByteArray)
181
       */
182
      public PublicKeyCredentialRequestOptionsBuilder challenge(ByteArray challenge) {
183 1 1. challenge : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder$MandatoryStages::challenge → KILLED
        return builder.challenge(challenge);
184
      }
185
    }
186
187
    /**
188
     * Specifies a time, in milliseconds, that the caller is willing to wait for the call to
189
     * complete.
190
     *
191
     * <p>This is treated as a hint, and MAY be overridden by the client.
192
     */
193 1 1. timeout : negated conditional → KILLED
    public PublicKeyCredentialRequestOptionsBuilder timeout(@NonNull Optional<Long> timeout) {
194
      this.timeout = timeout.orElse(null);
195 1 1. timeout : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → KILLED
      return this;
196
    }
197
198
    /*
199
     * Workaround, see: https://github.com/rzwitserloot/lombok/issues/2623#issuecomment-714816001
200
     * Consider reverting this workaround if Lombok fixes that issue.
201
     */
202
    private PublicKeyCredentialRequestOptionsBuilder timeout(Long timeout) {
203 1 1. timeout : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → KILLED
      return this.timeout(Optional.ofNullable(timeout));
204
    }
205
206
    /**
207
     * Specifies a time, in milliseconds, that the caller is willing to wait for the call to
208
     * complete.
209
     *
210
     * <p>This is treated as a hint, and MAY be overridden by the client.
211
     */
212
    public PublicKeyCredentialRequestOptionsBuilder timeout(long timeout) {
213 1 1. timeout : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → NO_COVERAGE
      return this.timeout(Optional.of(timeout));
214
    }
215
216
    /**
217
     * Specifies the relying party identifier claimed by the caller.
218
     *
219
     * <p>If omitted, its value will be set by the client.
220
     */
221 1 1. rpId : negated conditional → KILLED
    public PublicKeyCredentialRequestOptionsBuilder rpId(@NonNull Optional<String> rpId) {
222 1 1. rpId : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::rpId → KILLED
      return this.rpId(rpId.orElse(null));
223
    }
224
225
    /**
226
     * Specifies the relying party identifier claimed by the caller.
227
     *
228
     * <p>If omitted, its value will be set by the client.
229
     */
230
    public PublicKeyCredentialRequestOptionsBuilder rpId(String rpId) {
231
      this.rpId = rpId;
232 1 1. rpId : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::rpId → KILLED
      return this;
233
    }
234
235
    /**
236
     * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials
237
     * acceptable to the caller, in descending order of the caller’s preference (the first item in
238
     * the list is the most preferred credential, and so on down the list).
239
     */
240
    public PublicKeyCredentialRequestOptionsBuilder allowCredentials(
241 1 1. allowCredentials : negated conditional → KILLED
        @NonNull Optional<List<PublicKeyCredentialDescriptor>> allowCredentials) {
242 1 1. allowCredentials : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::allowCredentials → KILLED
      return this.allowCredentials(allowCredentials.orElse(null));
243
    }
244
245
    /**
246
     * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials
247
     * acceptable to the caller, in descending order of the caller’s preference (the first item in
248
     * the list is the most preferred credential, and so on down the list).
249
     */
250
    public PublicKeyCredentialRequestOptionsBuilder allowCredentials(
251
        List<PublicKeyCredentialDescriptor> allowCredentials) {
252
      this.allowCredentials = allowCredentials;
253 1 1. allowCredentials : replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::allowCredentials → KILLED
      return this;
254
    }
255
  }
256
}

Mutations

113

1.1
Location : <init>
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
negated conditional → KILLED

118

1.1
Location : <init>
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
negated conditional → KILLED

123

1.1
Location : <init>
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
negated conditional → KILLED

129

1.1
Location : getTimeout
Killed by : com.yubico.webauthn.RelyingPartyStartOperationSpec
replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getTimeout → KILLED

133

1.1
Location : getAllowCredentials
Killed by : com.yubico.webauthn.RelyingPartyStartOperationSpec
replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getAllowCredentials → KILLED

137

1.1
Location : getUserVerification
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with Optional.empty for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::getUserVerification → KILLED

160

1.1
Location : toCredentialsGetJson
Killed by : com.yubico.webauthn.data.JsonIoSpec
replaced return value with "" for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::toCredentialsGetJson → KILLED

164

1.1
Location : builder
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions::builder → KILLED

183

1.1
Location : challenge
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder$MandatoryStages::challenge → KILLED

193

1.1
Location : timeout
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
negated conditional → KILLED

195

1.1
Location : timeout
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → KILLED

203

1.1
Location : timeout
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → KILLED

213

1.1
Location : timeout
Killed by : none
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::timeout → NO_COVERAGE

221

1.1
Location : rpId
Killed by : com.yubico.webauthn.RelyingPartyStartOperationSpec
negated conditional → KILLED

222

1.1
Location : rpId
Killed by : com.yubico.webauthn.RelyingPartyStartOperationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::rpId → KILLED

232

1.1
Location : rpId
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::rpId → KILLED

241

1.1
Location : allowCredentials
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
negated conditional → KILLED

242

1.1
Location : allowCredentials
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::allowCredentials → KILLED

253

1.1
Location : allowCredentials
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
replaced return value with null for com/yubico/webauthn/data/PublicKeyCredentialRequestOptions$PublicKeyCredentialRequestOptionsBuilder::allowCredentials → KILLED

Active mutators

Tests examined


Report generated by PIT 1.15.0