/// <summary> /// Obtains the claims supported by this Identity Server for this client as a JSON string. /// </summary> /// <param name="userCredentialsCallback"> /// A callback used to obtain login credentials in the case that the current Access Token and /// Refresh Token (if any) are expired. /// </param> /// <returns>A JSON string representing the Claims for this API.</returns> /// public async Task <string> GetAccountsApiClaimsAsJson(UserCredentialsCallback userCredentialsCallback) { var response = await InvokeApiAsync(Get, "identity", userCredentialsCallback); var content = await TryGetResponseContent(response); return(content); }
/// <summary> /// Used by Admin users to create a new account bound to the client specified by <c>clientId</c>. /// </summary> /// <param name="clientId">The account to be modified.</param> /// <param name="userCredentialsCallback">A delegate that, if invoked, returns the User's credentials.</param> /// <returns>The starting balance for the new account.</returns> /// public async Task <string> CreateAccount(string clientId, UserCredentialsCallback userCredentialsCallback) { string accountId; var accessToken = await GetCurrentAccessToken(userCredentialsCallback); using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { accountId = await accountsApi.CreateAccount(clientId); } return(accountId); }
/// <summary> /// Get the history of an account from the Accounts API, on behalf of a User. /// </summary> /// <param name="accountNumber">The account to be queried.</param> /// <param name="userCredentialsCallback">A delegate that, if invoked, returns the User's credentials.</param> /// <returns>The account history as list of signed doubles.</returns> /// public async Task <AccountHistory> GetAccountHistory(string accountNumber, UserCredentialsCallback userCredentialsCallback) { AccountHistory history; var accessToken = await GetCurrentAccessToken(userCredentialsCallback); using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { history = await accountsApi.GetAccountHistory(accountNumber); } return(history); }
/// <summary> /// Get the balance of an account from the Accounts API, on behalf of a User. /// </summary> /// <param name="accountNumber">The account to be queried.</param> /// <param name="userCredentialsCallback">A delegate that, if invoked, returns the User's credentials.</param> /// <returns>The account balance as a double.</returns> /// public async Task <double> GetAccountBalance(string accountNumber, UserCredentialsCallback userCredentialsCallback) { double balance; var accessToken = await GetCurrentAccessToken(userCredentialsCallback); using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { balance = await accountsApi.GetAccountBalance(accountNumber); } return(balance); }
private async Task <string> GetCurrentAccessToken(UserCredentialsCallback userCredentialsCallback) { var tokens = TokenManager.GetAccessTokens(); if (!String.IsNullOrEmpty(tokens?.AccessToken)) { return(tokens.AccessToken); } var(username, password) = await userCredentialsCallback(); return(await GetAndStoreApiAccessTokens(username, password)); }
/// <summary> /// Create a Client with and bind it to the specified username. This request will fail if the User /// specified by <c>username</c> is already bound to a Client. /// </summary> /// <param name="username">The username of the User to bind to the new Client.</param> /// <param name="firstName">The client's first/given name.</param> /// <param name="lastName">The client's last/family name.</param> /// <param name="userCredentialsCallback"></param> /// <returns></returns> public async Task <string> CreateClient(string username, string firstName, string lastName, UserCredentialsCallback userCredentialsCallback) { var accessToken = await GetCurrentAccessToken(userCredentialsCallback); using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { var clientId = await accountsApi.CreateClient(username, firstName, lastName); return(clientId); } }
/// <summary> /// Call the Accounts API, on behalf of a User, to debit an account by some amount. /// Note that <c>amount</c> should be unsigned, and that only it's absolute value /// will be taken in any event. /// </summary> /// <param name="accountNumber">The account to be modified.</param> /// <param name="amount">The (unsigned) amount to be debited from the account.</param> /// <param name="memo">A short note to be attached to this transaction.</param> /// <param name="userCredentialsCallback">A delegate that, if invoked, returns the User's credentials.</param> /// <returns>The new balance for the modified account.</returns> /// public async Task <double> DebitAccount(string accountNumber, double amount, string memo, UserCredentialsCallback userCredentialsCallback) { double balance; var accessToken = await GetCurrentAccessToken(userCredentialsCallback); using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { balance = await accountsApi.DebitAccount(accountNumber, amount, memo); } return(balance); }
/// <summary> /// Creates a new Identity with the specified username, password, and name. Also creates a corresponding /// User on the Accounts system and links it to the new Identity via the <see cref="ApplicationClaimTypes.ACCOUNTS_USERNAME"/> /// claim. /// </summary> /// <param name="username"></param> /// <param name="password"></param> /// <param name="firstName"></param> /// <param name="lastName"></param> /// <param name="isAdmin"></param> /// <param name="userCredentialsCallback"></param> /// <returns></returns> public async Task CreateUser(string username, string password, string firstName, string lastName, bool isAdmin, UserCredentialsCallback userCredentialsCallback) { var accessToken = await GetCurrentAccessToken(userCredentialsCallback); var newUser = new AltSourceNewUserDto(username, password, firstName, lastName, isAdmin); var jsonNewUser = JsonConvert.SerializeObject(newUser); var content = new StringContent(jsonNewUser, Encoding.UTF8, "application/json"); using (var identityApi = new HttpClient { BaseAddress = _identityServerUrl }) { identityApi.SetBearerToken(accessToken); var requestUrl = (isAdmin ? "api/manage/admin/create" : "api/manage/user/create"); var result = await identityApi.PutAsync(requestUrl, content); if (!result.IsSuccessStatusCode) { var msg = result.Content.ReadAsStringAsync(); throw new HttpRequestException($"{result.ReasonPhrase} - {msg.Result}"); } } using (var accountsApi = new AccountsApiClient(_accountsApiUrl, accessToken)) { if (!await accountsApi.CreateUser(username)) { throw new HttpRequestException($"Failed to create user '{username}' on the Accounts system."); } } }
/// <summary> /// Submits a request URL to the Accounts API. Contains the retry logic required in order to /// deal with expired Access/Refresh Tokens. /// </summary> /// <param name="invocation">The calling method (Get, Put, or Post).</param> /// <param name="requestUrn">The request to be submitted to the Accounts API. /// See: <see cref="InvokeApiAsync(HttpClientHelpers.EndPointInvocation,string)"/> /// </param> /// <param name="userCredentialsCallback"> /// A delegate that can be invoked to obtain username/password credentials from the user. /// </param> /// <returns>The response from the Accounts API.</returns> /// private async Task <HttpResponseMessage> InvokeApiAsync(HttpClientHelpers.EndPointInvocation invocation, string requestUrn, UserCredentialsCallback userCredentialsCallback) { // ReSharper disable once NotAccessedVariable AccessTokenPair accessTokens; //-------------------------------------------------------------------------------------------- // Have we been authenticated? Check the Token Manager for an Access Token. If we don't have // one, go get one. //-------------------------------------------------------------------------------------------- // ReSharper disable once RedundantAssignment if ((accessTokens = TokenManager.GetAccessTokens()).IsNull()) { var(username, password) = await userCredentialsCallback(); await GetAndStoreApiAccessTokens(username, password); } // TODO handle failure //-------------------------------------------------------------------------------------------- // We have an Access Token; issue the request to the Accounts API. //-------------------------------------------------------------------------------------------- var response = await InvokeApiAsync(invocation, requestUrn); //-------------------------------------------------------------------------------------------- // Did the request fail? //-------------------------------------------------------------------------------------------- if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); //------------------------------------------------------------------------------------------ // Failed. Was it because our access token timed out? //------------------------------------------------------------------------------------------ if (response.IsAccessTokenExpired()) { //---------------------------------------------------------------------------------------- // Yes. Use our refresh token to get a new access token. //---------------------------------------------------------------------------------------- // ReSharper disable once NotAccessedVariable var accessToken = await GetAndStoreApiAccessTokens(); //---------------------------------------------------------------------------------------- // Re-submit the original request with the new access token. //---------------------------------------------------------------------------------------- response = await InvokeApiAsync(invocation, requestUrn); //---------------------------------------------------------------------------------------- // Is the Accounts API still reporting an expired token? //---------------------------------------------------------------------------------------- if (response.IsAccessTokenExpired()) { //-------------------------------------------------------------------------------------- // Yes. Apparently, our refresh token has expired too. At this point we must ask the // user to re-authenticate with their username/password. Use the caller-provided // callback to obtain them. //-------------------------------------------------------------------------------------- var(username, password) = await userCredentialsCallback(); //-------------------------------------------------------------------------------------- // Try to get a new access token one more time, using the user's credentials. //-------------------------------------------------------------------------------------- // ReSharper disable once RedundantAssignment accessToken = await GetAndStoreApiAccessTokens(username, password); //-------------------------------------------------------------------------------------- // Either that worked, or it didn't. Either way, we're done here. Return the final // response to the caller. //-------------------------------------------------------------------------------------- response = await InvokeApiAsync(invocation, requestUrn); } } } return(response); }