summaryrefslogtreecommitdiffstats
path: root/dom/credentialmanagement/identity/IdentityCredential.h
blob: 598a8bf99ccaf63516e33d691e612c5421526ec5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_IdentityCredential_h
#define mozilla_dom_IdentityCredential_h

#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/Credential.h"
#include "mozilla/dom/IPCIdentityCredential.h"
#include "mozilla/MozPromise.h"

namespace mozilla::dom {

// This is the primary starting point for FedCM in the platform.
// This class is the implementation of the IdentityCredential object
// that is the value returned from the navigator.credentials.get call
// with an "identity" argument. It also includes static functions that
// perform operations that are used in constructing the credential.
class IdentityCredential final : public Credential {
 public:
  // These are promise types, all used to support the async implementation of
  // this API. All are of the form MozPromise<RefPtr<T>, nsresult>.
  // Tuples are included to shuffle additional values along, so that the
  // intermediate state is entirely in the promise chain and we don't have to
  // capture an early step's result into a callback for a subsequent promise.
  typedef MozPromise<RefPtr<IdentityCredential>, nsresult, true>
      GetIdentityCredentialPromise;
  typedef MozPromise<IPCIdentityCredential, nsresult, true>
      GetIPCIdentityCredentialPromise;
  typedef MozPromise<IdentityProviderConfig, nsresult, true>
      GetIdentityProviderConfigPromise;
  typedef MozPromise<bool, nsresult, true> ValidationPromise;
  typedef MozPromise<IdentityProviderAPIConfig, nsresult, true>
      GetManifestPromise;
  typedef std::tuple<IdentityProviderConfig, IdentityProviderAPIConfig>
      IdentityProviderConfigWithManifest;
  typedef MozPromise<IdentityProviderConfigWithManifest, nsresult, true>
      GetIdentityProviderConfigWithManifestPromise;
  typedef MozPromise<
      std::tuple<IdentityProviderAPIConfig, IdentityProviderAccountList>,
      nsresult, true>
      GetAccountListPromise;
  typedef MozPromise<std::tuple<IdentityProviderToken, IdentityProviderAccount>,
                     nsresult, true>
      GetTokenPromise;
  typedef MozPromise<
      std::tuple<IdentityProviderAPIConfig, IdentityProviderAccount>, nsresult,
      true>
      GetAccountPromise;
  typedef MozPromise<IdentityProviderClientMetadata, nsresult, true>
      GetMetadataPromise;

  // This needs to be constructed in the context of a window
  explicit IdentityCredential(nsPIDOMWindowInner* aParent);

 protected:
  ~IdentityCredential() override;

 public:
  virtual JSObject* WrapObject(JSContext* aCx,
                               JS::Handle<JSObject*> aGivenProto) override;

  // This builds a value from an IPC-friendly version. This type is returned
  // to the caller of navigator.credentials.get, however we get an IPC friendly
  // version back from the main process to the content process.
  // This is a deep copy of the token, ID, and type.
  void CopyValuesFrom(const IPCIdentityCredential& aOther);

  // This is the inverse of CopyValuesFrom. Included for completeness.
  IPCIdentityCredential MakeIPCIdentityCredential();

  // Getter and setter for the token member of this class
  void GetToken(nsAString& aToken) const;
  void SetToken(const nsAString& aToken);

  // This function allows a relying party to send one last credentialed request
  // to the IDP when logging out. This only works if the current account state
  // in the IdentityCredentialStorageService allows logouts and clears that bit
  // when a request is sent.
  //
  //  Arguments:
  //    aGlobal: the global of the window calling this function
  //    aLogoutRequest: all of the logout requests to try to send.
  //        This is pairs of the IDP's logout url and the account
  //        ID for that IDP.
  //  Return value:
  //    a promise resolving to undefined
  //  Side effects:
  //    Will send a network request to each IDP that have a state allowing
  //        logouts and disables that bit.
  static already_AddRefed<Promise> LogoutRPs(
      GlobalObject& aGlobal,
      const Sequence<IdentityCredentialLogoutRPsRequest>& aLogoutRequests,
      ErrorResult& aRv);

  // This is the main static function called when a credential needs to be
  // fetched from the IDP. Called in the content process.
  // This is mostly a passthrough to `DiscoverFromExternalSourceInMainProcess`.
  static RefPtr<GetIdentityCredentialPromise> DiscoverFromExternalSource(
      nsPIDOMWindowInner* aParent, const CredentialRequestOptions& aOptions,
      bool aSameOriginWithAncestors);

  // Start the FedCM flow. This will start the timeout timer, fire initial
  // network requests, prompt the user, and call into CreateCredential.
  //
  //   Arguments:
  //     aPrincipal: the caller of navigator.credentials.get()'s principal
  //     aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //     aOptions: argument passed to navigator.credentials.get()
  //  Return value:
  //    a promise resolving to an IPC credential with type "identity", id
  //    constructed to identify it, and token corresponding to the token
  //    fetched in FetchToken. This promise may reject with nsresult errors.
  //  Side effects:
  //    Will send network requests to the IDP. The details of which are in the
  //    other static methods here.
  static RefPtr<GetIPCIdentityCredentialPromise>
  DiscoverFromExternalSourceInMainProcess(
      nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
      const IdentityCredentialRequestOptions& aOptions);

  // Create an IPC credential that can be passed back to the content process.
  // This calls a lot of helpers to do the logic of going from a single provider
  // to a bearer token for an account at that provider.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //    aProvider: the provider to validate the root manifest of
  //    aManifest: the internal manifest of the identity provider
  //  Return value:
  //    a promise resolving to an IPC credential with type "identity", id
  //    constructed to identify it, and token corresponding to the token
  //    fetched in FetchToken. This promise may reject with nsresult errors.
  //  Side effects:
  //    Will send network requests to the IDP. The details of which are in the
  //    other static methods here.
  static RefPtr<GetIPCIdentityCredentialPromise> CreateCredential(
      nsIPrincipal* aPrincipal, BrowsingContext* aBrowsingContext,
      const IdentityProviderConfig& aProvider,
      const IdentityProviderAPIConfig& aManifest);

  // Performs a Fetch for the root manifest of the provided identity provider
  // and validates it as correct. The returned promise resolves with a bool
  // that is true if everything is valid.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aProvider: the provider to validate the root manifest of
  //  Return value:
  //    promise that resolves to a bool that indicates success. Will reject
  //    when there are network or other errors.
  //  Side effects:
  //    Network request to the IDP's well-known from inside a NullPrincipal
  //    sandbox
  //
  static RefPtr<ValidationPromise> CheckRootManifest(
      nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider);

  // Performs a Fetch for the internal manifest of the provided identity
  // provider. The returned promise resolves with the manifest retrieved.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aProvider: the provider to fetch the root manifest
  //  Return value:
  //    promise that resolves to the internal manifest. Will reject
  //    when there are network or other errors.
  //  Side effects:
  //    Network request to the URL in aProvider as the manifest from inside a
  //    NullPrincipal sandbox
  //
  static RefPtr<GetManifestPromise> FetchInternalManifest(
      nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider);

  // Performs a Fetch for the account list from the provided identity
  // provider. The returned promise resolves with the manifest and the fetched
  // account list in a tuple of objects. We put the argument manifest in the
  // tuple to facilitate clean promise chaining.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aProvider: the provider to get account lists from
  //    aManifest: the provider's internal manifest
  //  Return value:
  //    promise that resolves to a Tuple of the passed manifest and the fetched
  //    account list. Will reject when there are network or other errors.
  //  Side effects:
  //    Network request to the provider supplied account endpoint with
  //    credentials but without any indication of aPrincipal.
  //
  static RefPtr<GetAccountListPromise> FetchAccountList(
      nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider,
      const IdentityProviderAPIConfig& aManifest);

  // Performs a Fetch for a bearer token to the provided identity
  // provider for a given account. The returned promise resolves with the
  // account argument and the fetched token in a tuple of objects.
  // We put the argument account in the
  // tuple to facilitate clean promise chaining.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aProvider: the provider to get account lists from
  //    aManifest: the provider's internal manifest
  //    aAccount: the account to request
  //  Return value:
  //    promise that resolves to a Tuple of the passed account and the fetched
  //    token. Will reject when there are network or other errors.
  //  Side effects:
  //    Network request to the provider supplied token endpoint with
  //    credentials and including information about the requesting principal.
  //
  static RefPtr<GetTokenPromise> FetchToken(
      nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider,
      const IdentityProviderAPIConfig& aManifest,
      const IdentityProviderAccount& aAccount);

  // Performs a Fetch for links to legal info about the identity provider.
  // The returned promise resolves with the information in an object.
  //
  //  Arguments:
  //    aPrincipal: the caller of navigator.credentials.get()'s principal
  //    aProvider: the identity provider to get information from
  //    aManfiest: the identity provider's manifest
  //  Return value:
  //    promise that resolves with an object containing legal information for
  //    aProvider
  //  Side effects:
  //    Network request to the provider supplied token endpoint with
  //    credentials and including information about the requesting principal.
  //
  static RefPtr<GetMetadataPromise> FetchMetadata(
      nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider,
      const IdentityProviderAPIConfig& aManifest);

  // Show the user a dialog to select what identity provider they would like
  // to try to log in with.
  //
  //   Arguments:
  //    aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //    aProviders: the providers to let the user select from
  //    aManifests: the manifests
  //  Return value:
  //    a promise resolving to an identity provider that the user took action
  //    to select. This promise may reject with nsresult errors.
  //  Side effects:
  //    Will show a dialog to the user.
  static RefPtr<GetIdentityProviderConfigWithManifestPromise>
  PromptUserToSelectProvider(
      BrowsingContext* aBrowsingContext,
      const Sequence<IdentityProviderConfig>& aProviders,
      const Sequence<GetManifestPromise::ResolveOrRejectValue>& aManifests);

  // Show the user a dialog to select what account they would like
  // to try to log in with.
  //
  //   Arguments:
  //    aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //    aAccounts: the accounts to let the user select from
  //    aProvider: the provider that was chosen
  //    aManifest: the identity provider that was chosen's manifest
  //  Return value:
  //    a promise resolving to an account that the user took action
  //    to select (and aManifest). This promise may reject with nsresult errors.
  //  Side effects:
  //    Will show a dialog to the user.
  static RefPtr<GetAccountPromise> PromptUserToSelectAccount(
      BrowsingContext* aBrowsingContext,
      const IdentityProviderAccountList& aAccounts,
      const IdentityProviderConfig& aProvider,
      const IdentityProviderAPIConfig& aManifest);

  // Show the user a dialog to select what account they would like
  // to try to log in with.
  //
  //   Arguments:
  //    aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //    aAccount: the accounts the user chose
  //    aManifest: the identity provider that was chosen's manifest
  //    aProvider: the identity provider that was chosen
  //  Return value:
  //    a promise resolving to an account that the user agreed to use (and
  //    aManifest). This promise may reject with nsresult errors. This includes
  //    if the user denied the terms and privacy policy
  //  Side effects:
  //    Will show a dialog to the user. Will send a network request to the
  //    identity provider. Modifies the IdentityCredentialStorageService state
  //    for this account.
  static RefPtr<GetAccountPromise> PromptUserWithPolicy(
      BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
      const IdentityProviderAccount& aAccount,
      const IdentityProviderAPIConfig& aManifest,
      const IdentityProviderConfig& aProvider);

  // Close all dialogs associated with IdentityCredential generation on the
  // provided browsing context
  //
  //   Arguments:
  //    aBrowsingContext: the BC of the caller of navigator.credentials.get()
  //  Side effects:
  //    Will close a dialog shown to the user.
  static void CloseUserInterface(BrowsingContext* aBrowsingContext);

 private:
  nsAutoString mToken;
};

}  // namespace mozilla::dom

#endif  // mozilla_dom_IdentityCredential_h