/// <summary>
        /// Handles continuation of the process following a completed redirect, the request token url must be provided if it has been returned by the discovery process.
        /// Only the request and redirectedUrl are required, however if the redirect being handled is the result of calling the Authorization URL then the remaining parameters are required.
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="redirectedUrl">Url redirected to by the completion of the previous step</param>
        /// <param name="sdkSession">SDKSession id used to fetch the discovery response with additional parameters that are required to request a token</param>
        /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
        /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
        /// <param name="options">Optional parameters</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> HandleUrlRedirectAsync(
            HttpRequestMessage request,
            Uri redirectedUrl,
            string sdkSession    = null,
            string expectedState = null,
            string expectedNonce = null,
            MobileConnectRequestOptions options = null, string version = null)
        {
            var discoveryResponse = await GetSessionFromCache(sdkSession);

            if (discoveryResponse == null && (expectedNonce != null || expectedState != null || sdkSession != null))
            {
                return(GetCacheError());
            }

            return(await CacheIfRequired(
                       await MobileConnectInterfaceHelper.HandleUrlRedirect(
                           _discovery,
                           _authentication,
                           _jwks,
                           redirectedUrl,
                           discoveryResponse,
                           expectedState,
                           expectedNonce,
                           _config,
                           options, version)));
        }
        /// <summary>
        /// Performs headless authentication followed by request token if successful. Tokens will be validated before being returned.
        /// This may be a long running method as it waits for the authenticating user to respond using their authenticating device.
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="discoveryResponse">The response returned by the discovery process</param>
        /// <param name="encryptedMSISDN">Encrypted MSISDN/Subscriber Id returned from the Discovery process</param>
        /// <param name="state">Unique string to be used to prevent Cross Site Forgery Request attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="nonce">Unique string to be used to prevent replay attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="options">Optional parameters</param>
        /// <param name="cancellationToken">Cancellation token that can be used to cancel long running requests</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> RequestHeadlessAuthenticationAsync(
            HttpRequestMessage request,
            DiscoveryResponse discoveryResponse,
            string encryptedMSISDN,
            string state,
            string nonce,
            MobileConnectRequestOptions options,
            string version,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            state = string.IsNullOrEmpty(state) ? Security.GenerateSecureNonce() : state;
            nonce = string.IsNullOrEmpty(nonce) ? Security.GenerateSecureNonce() : nonce;

            return(await MobileConnectInterfaceHelper.RequestHeadlessAuthentication(
                       _authentication,
                       _jwks,
                       _identity,
                       discoveryResponse,
                       encryptedMSISDN,
                       state,
                       nonce,
                       _config,
                       options, version,
                       cancellationToken));
        }
 /// <summary>
 /// Request identity using the access token returned by <see cref="RequestTokenAsync(HttpRequestMessage, DiscoveryResponse, Uri, string, string, MobileConnectRequestOptions)"/>
 /// </summary>
 /// <param name="request">Originating web request</param>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="accessToken">Access token returned from RequestToken required to authenticate the request</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with requested Identity information</returns>
 public async Task <MobileConnectStatus> RequestPremiumInfoAsync(
     HttpRequestMessage request,
     DiscoveryResponse discoveryResponse,
     string accessToken,
     MobileConnectRequestOptions options)
 {
     return(await MobileConnectInterfaceHelper.RequestPremiumInfo(
                _identity, discoveryResponse, accessToken, _config, options));
 }
Пример #4
0
 /// <summary>
 /// Creates an authorization url with parameters to begin the authorization process
 /// </summary>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="encryptedMSISDN">Encrypted MSISDN/Subscriber Id returned from the Discovery process</param>
 /// <param name="state">Unique state value, this will be returned by the authorization process and should be checked for equality as a security measure</param>
 /// <param name="nonce">Unique value to associate a client session with an id token</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public MobileConnectStatus StartAuthentication(
     DiscoveryResponse discoveryResponse,
     string encryptedMSISDN,
     string state,
     string nonce,
     MobileConnectRequestOptions options,
     string version)
 {
     return(MobileConnectInterfaceHelper.StartAuthentication(
                _authentication, discoveryResponse, encryptedMSISDN, state, nonce, _config, options, version));
 }
        /// <summary>
        /// Performs headless authentication followed by request token if successful. Tokens will be validated before being returned.
        /// This may be a long running method as it waits for the authenticating user to respond using their authenticating device.
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="sdkSession">SDKSession id used to fetch the discovery response with additional parameters that are required to generate the url</param>
        /// <param name="encryptedMSISDN">Encrypted MSISDN/Subscriber Id returned from the Discovery process</param>
        /// <param name="state">Unique string to be used to prevent Cross Site Forgery Request attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="nonce">Unique string to be used to prevent replay attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="options">Optional parameters</param>
        /// <param name="cancellationToken">Cancellation token that can be used to cancel long running requests</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> RequestHeadlessAuthenticationAsync(HttpRequestMessage request, string sdkSession, string encryptedMSISDN, string state, string nonce,
                                                                                   MobileConnectRequestOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            var discoveryResponse = await GetSessionFromCache(sdkSession);

            if (discoveryResponse == null)
            {
                return(GetCacheError());
            }

            return(await RequestHeadlessAuthenticationAsync(request, discoveryResponse, encryptedMSISDN, state, nonce, options, cancellationToken));
        }
        /// <summary>
        /// Request identity using the access token returned by <see cref="RequestTokenAsync(HttpRequestMessage, DiscoveryResponse, Uri, string, string, MobileConnectRequestOptions)"/>
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="sdkSession">SDKSession id used to fetch the discovery response with additional parameters that are required to request a user info</param>
        /// <param name="accessToken">Access token returned from RequestToken required to authenticate the request</param>
        /// <param name="options">Additional optional parameters</param>
        /// <returns>MobileConnectStatus object with requested Identity information</returns>
        public async Task <MobileConnectStatus> RequestPremiumInfoAsync(
            HttpRequestMessage request, string sdkSession, string accessToken, MobileConnectRequestOptions options)
        {
            var discoveryResponse = await GetSessionFromCache(sdkSession);

            if (discoveryResponse == null)
            {
                return(GetCacheError());
            }

            return(await RequestPremiumInfoAsync(request, discoveryResponse, accessToken, options));
        }
        /// <summary>
        /// Creates an authorization url with parameters to begin the authetication process
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="discoveryResponse">The response returned by the discovery process</param>
        /// <param name="encryptedMSISDN">Encrypted MSISDN/Subscriber Id returned from the Discovery process</param>
        /// <param name="state">Unique string to be used to prevent Cross Site Forgery Request attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="nonce">Unique string to be used to prevent replay attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="options">Optional parameters</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public MobileConnectStatus StartAuthentication(
            HttpRequestMessage request,
            DiscoveryResponse discoveryResponse,
            string encryptedMSISDN,
            string state,
            string nonce,
            MobileConnectRequestOptions options,
            string version)
        {
            state = string.IsNullOrEmpty(state) ? Security.GenerateSecureNonce() : state;
            nonce = string.IsNullOrEmpty(nonce) ? Security.GenerateSecureNonce() : nonce;

            return(MobileConnectInterfaceHelper.StartAuthentication(
                       _authentication, discoveryResponse, encryptedMSISDN, state, nonce, _config, options, version));
        }
        /// <summary>
        /// Attempt discovery using the supplied parameters. If msisdn, mcc and mnc are null the result
        /// will be operator selection, otherwise valid parameters will result in a StartAuthorization status
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="msisdn">MSISDN from user</param>
        /// <param name="mcc">Mobile Country Code</param>
        /// <param name="mnc">Mobile Network Code</param>
        /// <param name="shouldProxyCookies">If cookies from the original request should be sent onto the discovery service</param>
        /// <param name="includeRequestIp">Including of remote ip address</param>
        /// <param name="options">Optional parameters</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> AttemptDiscoveryAsync(
            HttpRequestMessage request,
            string msisdn,
            string mcc,
            string mnc,
            bool shouldProxyCookies,
            bool includeRequestIp,
            MobileConnectRequestOptions options)
        {
            var cookies = shouldProxyCookies ? request.GetCookies() : null;

            return(await CacheIfRequired(
                       await MobileConnectInterfaceHelper.AttemptDiscovery(
                           _discovery, msisdn, mcc, mnc, cookies, _config, options)));
        }
        internal static async Task <MobileConnectStatus> AttemptDiscovery(
            IDiscoveryService discovery,
            string msisdn,
            string mcc,
            string mnc,
            IEnumerable <BasicKeyValuePair> cookies,
            MobileConnectConfig config,
            MobileConnectRequestOptions options)
        {
            DiscoveryResponse response = null;

            try
            {
                DiscoveryOptions discoveryOptions = options?.DiscoveryOptions ?? new DiscoveryOptions();
                discoveryOptions.MSISDN        = msisdn;
                discoveryOptions.IdentifiedMCC = mcc;
                discoveryOptions.IdentifiedMNC = mnc;
                discoveryOptions.RedirectUrl   = config.RedirectUrl;
                discoveryOptions.XRedirect     = config.XRedirect;

                response = await discovery.StartAutomatedOperatorDiscoveryAsync(
                    config, config.RedirectUrl, discoveryOptions, cookies);
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to AttemptDiscovery arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument,
                                                 string.Format("An argument was found to be invalid during the process. The argument was {0}.",
                                                               e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                Log.Error(() => $"A general http error occurred in AttemptDiscovery msisdn={!string.IsNullOrEmpty(msisdn)} mcc={mcc} mnc={mnc} discoveryUrl={config.DiscoveryUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.HttpFailure,
                                                 "An HTTP failure occured while calling the discovery endpoint, the endpoint may be inaccessible",
                                                 e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in AttemptDiscovery msisdn={!string.IsNullOrEmpty(msisdn)} mcc={mcc} mnc={mnc} discoveryUrl={config.DiscoveryUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown,
                                                 "An unknown error occured while calling the Discovery service to obtain operator details",
                                                 e));
            }

            return(GenerateStatusFromDiscoveryResponse(discovery, response));
        }
Пример #10
0
 /// <summary>
 /// Synchronous wrapper for <see cref="MobileConnectInterface.RequestTokenAsync(DiscoveryResponse, Uri, string, string, MobileConnectRequestOptions)"/>
 /// </summary>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="redirectedUrl">Uri redirected to by the completion of the authorization UI</param>
 /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
 /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public MobileConnectStatus RequestToken(
     DiscoveryResponse discoveryResponse,
     Uri redirectedUrl,
     string expectedState,
     string expectedNonce,
     MobileConnectRequestOptions options, string version)
 {
     return(MobileConnectInterfaceHelper.RequestToken(
                _authentication,
                _jwks,
                discoveryResponse,
                redirectedUrl,
                expectedState,
                expectedNonce,
                _config,
                options, version).Result);
 }
Пример #11
0
 /// <summary>
 /// Synchronous wrapper for <see cref="MobileConnectInterface.HandleUrlRedirectAsync(Uri, DiscoveryResponse, string, string, MobileConnectRequestOptions)"/>
 /// </summary>
 /// <param name="redirectedUrl">Url redirected to by the completion of the previous step</param>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
 /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public MobileConnectStatus HandleUrlRedirect(
     Uri redirectedUrl,
     DiscoveryResponse discoveryResponse = null,
     string expectedState = null,
     string expectedNonce = null,
     MobileConnectRequestOptions options = null, string version = null)
 {
     return(MobileConnectInterfaceHelper.HandleUrlRedirect(
                _discovery,
                _authentication,
                _jwks,
                redirectedUrl,
                discoveryResponse,
                expectedState,
                expectedNonce,
                _config,
                options, version).Result);
 }
 /// <summary>
 /// Request token using the values returned from the authorization redirect
 /// </summary>
 /// <param name="request">Originating web request</param>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="redirectedUrl">Uri redirected to by the completion of the authorization UI</param>
 /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
 /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public async Task <MobileConnectStatus> RequestTokenAsync(
     HttpRequestMessage request,
     DiscoveryResponse discoveryResponse,
     Uri redirectedUrl,
     string expectedState,
     string expectedNonce,
     MobileConnectRequestOptions options, string version)
 {
     return(await MobileConnectInterfaceHelper.RequestToken(
                _authentication,
                _jwks,
                discoveryResponse,
                redirectedUrl,
                expectedState,
                expectedNonce,
                _config,
                options, version));
 }
        /// <summary>
        /// Request token using the values returned from the authorization redirect
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="sdkSession">SDKSession id used to fetch the discovery response with additional parameters that are required to request a token</param>
        /// <param name="redirectedUrl">Uri redirected to by the completion of the authorization UI</param>
        /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
        /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
        /// <param name="options">Optional parameters</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> RequestTokenAsync(
            HttpRequestMessage request,
            string sdkSession,
            Uri redirectedUrl,
            string expectedState,
            string expectedNonce,
            MobileConnectRequestOptions options, string version)
        {
            var discoveryResponse = await GetSessionFromCache(sdkSession);

            if (discoveryResponse == null)
            {
                return(GetCacheError());
            }

            return(await RequestTokenAsync(
                       request, discoveryResponse, redirectedUrl, expectedState, expectedNonce, options, version));
        }
        /// <summary>
        /// Creates an authorization url with parameters to begin the authetication process, the SDKSession id is used to fetch the discovery response
        /// </summary>
        /// <param name="request">Originating web request</param>
        /// <param name="sdkSession">SDKSession id used to fetch the discovery response with additional parameters that are required to generate the url</param>
        /// <param name="encryptedMSISDN">Encrypted MSISDN/Subscriber Id returned from the Discovery process</param>
        /// <param name="state">Unique string to be used to prevent Cross Site Forgery Request attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="nonce">Unique string to be used to prevent replay attacks during request token process (defaults to guid if not supplied, value will be returned in MobileConnectStatus object)</param>
        /// <param name="options">Optional parameters</param>
        /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
        public async Task <MobileConnectStatus> StartAuthentication(
            HttpRequestMessage request,
            string sdkSession,
            string encryptedMSISDN,
            string state,
            string nonce,
            MobileConnectRequestOptions options,
            string version)
        {
            var discoveryResponse = await GetSessionFromCache(sdkSession);

            if (discoveryResponse == null)
            {
                return(GetCacheError());
            }

            var authResult = StartAuthentication(request, discoveryResponse, encryptedMSISDN, state, nonce, options, version);

            return(authResult);
        }
 /// <summary>
 /// Handles continuation of the process following a completed redirect, the request token url must be provided if it has been returned by the discovery process.
 /// Only the request and redirectedUrl are required, however if the redirect being handled is the result of calling the Authorization URL then the remaining parameters are required.
 /// </summary>
 /// <param name="request">Originating web request</param>
 /// <param name="redirectedUrl">Url redirected to by the completion of the previous step</param>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="expectedState">The state value returned from the StartAuthorization call should be passed here, it will be used to validate the authenticity of the authorization process</param>
 /// <param name="expectedNonce">The nonce value returned from the StartAuthorization call should be passed here, it will be used to ensure the token was not requested using a replay attack</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public async Task <MobileConnectStatus> HandleUrlRedirectAsync(
     HttpRequestMessage request,
     Uri redirectedUrl,
     DiscoveryResponse
     discoveryResponse    = null,
     string expectedState = null,
     string expectedNonce = null,
     MobileConnectRequestOptions options = null, string version = null)
 {
     return(await CacheIfRequired(
                await MobileConnectInterfaceHelper.HandleUrlRedirect(
                    _discovery,
                    _authentication,
                    _jwks,
                    redirectedUrl,
                    discoveryResponse,
                    expectedState,
                    expectedNonce,
                    _config,
                    options, version)));
 }
 /// <summary>
 /// Request user info using the access token returned by <see cref="RequestTokenAsync(DiscoveryResponse, Uri, string, string, MobileConnectRequestOptions)"/>
 /// </summary>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="accessToken">Access token from RequestToken stage</param>
 /// <param name="options">Additional optional parameters</param>
 /// <returns>MobileConnectStatus object with UserInfo information</returns>
 public async Task <MobileConnectStatus> RequestIdentityAsync(DiscoveryResponse discoveryResponse, string accessToken, MobileConnectRequestOptions options)
 {
     return(await MobileConnectInterfaceHelper.RequestIdentity(_identity, discoveryResponse, accessToken, _config, options));
 }
Пример #17
0
 /// <summary>
 /// Synchronous wrapper for <see cref="MobileConnectInterface.AttemptDiscoveryAsync(string, string, string, MobileConnectRequestOptions)"/>
 /// </summary>
 /// <param name="msisdn">MSISDN from user</param>
 /// <param name="mcc">Mobile Country Code</param>
 /// <param name="mnc">Mobile Network Code</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public MobileConnectStatus AttemptDiscovery(string msisdn, string mcc, string mnc, MobileConnectRequestOptions options)
 {
     return(AttemptDiscoveryAsync(msisdn, mcc, mnc, options).Result);
 }
        internal static MobileConnectStatus StartAuthentication(IAuthenticationService authentication, DiscoveryResponse discoveryResponse, string encryptedMSISDN,
                                                                string state, string nonce, MobileConnectConfig config, MobileConnectRequestOptions options)
        {
            if (!IsUsableDiscoveryResponse(discoveryResponse))
            {
                return(MobileConnectStatus.StartDiscovery());
            }

            StartAuthenticationResponse response;

            try
            {
                string                clientId          = discoveryResponse.ResponseData.response.client_id ?? config.ClientId;
                string                authorizationUrl  = discoveryResponse.OperatorUrls.AuthorizationUrl;
                SupportedVersions     supportedVersions = discoveryResponse.ProviderMetadata?.MobileConnectVersionSupported;
                AuthenticationOptions authOptions       = options?.AuthenticationOptions ?? new AuthenticationOptions();
                authOptions.ClientName = discoveryResponse.ApplicationShortName;

                response = authentication.StartAuthentication(clientId, authorizationUrl, config.RedirectUrl, state, nonce, encryptedMSISDN, supportedVersions, authOptions);
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to StartAuthentication arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in AttemptDiscoveryAfterOperatorSelection state={state} nonce={nonce} authUrl={discoveryResponse.OperatorUrls.AuthorizationUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "An unknown error occured while generating an authorization url", e));
            }

            return(MobileConnectStatus.Authentication(response.Url, state, nonce));
        }
        internal static async Task <MobileConnectStatus> RequestIdentity(IIdentityService _identity, DiscoveryResponse discoveryResponse, string accessToken, MobileConnectConfig _config, MobileConnectRequestOptions options)
        {
            string identityUrl = discoveryResponse?.OperatorUrls?.PremiumInfoUrl;

            var notSupported = IsSupported(identityUrl, "Identity", discoveryResponse?.ProviderMetadata?.Issuer);

            if (notSupported != null)
            {
                return(notSupported);
            }

            try
            {
                var response = await _identity.RequestIdentity(identityUrl, accessToken);

                return(MobileConnectStatus.Identity(response));
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to RequestIdentity arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                Log.Error(() => $"A general http error occurred in RequestUserInfo identityUrl={identityUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.HttpFailure, "An HTTP failure occured while calling the operator token endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in RequestUserInfo identityUrl={identityUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "A failure occured while requesting a token", e));
            }
        }
        internal static async Task <MobileConnectStatus> RequestUserInfo(IIdentityService _identity, DiscoveryResponse discoveryResponse, string accessToken, MobileConnectConfig _config, MobileConnectRequestOptions options)
        {
            string userInfoUrl = discoveryResponse?.OperatorUrls?.UserInfoUrl;

            if (string.IsNullOrEmpty(userInfoUrl))
            {
                Log.Error(() => $"UserInfo was not supported for issuer={discoveryResponse?.ProviderMetadata?.Issuer}");
                return(MobileConnectStatus.Error(ErrorCodes.NotSupported, "UserInfo not supported with current operator", null));
            }

            try
            {
                var response = await _identity.RequestUserInfo(userInfoUrl, accessToken);

                return(MobileConnectStatus.UserInfo(response));
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to RequestUserInfo arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                Log.Error(() => $"A general http error occurred in RequestUserInfo userInfoUrl={userInfoUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.HttpFailure, "An HTTP failure occured while calling the operator token endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in RequestUserInfo userInfoUrl={userInfoUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "A failure occured while requesting a token", e));
            }
        }
        internal static async Task <MobileConnectStatus> HandleUrlRedirect(IDiscoveryService discovery, IAuthenticationService authentication, IJWKeysetService jwks, Uri redirectedUrl, DiscoveryResponse discoveryResponse,
                                                                           string expectedState, string expectedNonce, MobileConnectConfig config, MobileConnectRequestOptions options)
        {
            if (HttpUtils.ExtractQueryValue(redirectedUrl.Query, "code") != null)
            {
                return(await RequestToken(authentication, jwks, discoveryResponse, redirectedUrl, expectedState, expectedNonce, config, options));
            }
            else if (HttpUtils.ExtractQueryValue(redirectedUrl.Query, "mcc_mnc") != null)
            {
                return(await AttemptDiscoveryAfterOperatorSelection(discovery, redirectedUrl, config));
            }

            string errorCode = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "error") ?? ErrorCodes.InvalidRedirect;
            string errorDesc = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "error_description") ?? HttpUtils.ExtractQueryValue(redirectedUrl.Query, "description") ?? string.Format("Unable to parse next step using {0}", redirectedUrl.AbsoluteUri);

            return(MobileConnectStatus.Error(errorCode, errorDesc, null));
        }
        private static MobileConnectStatus HandleTokenResponse(IAuthenticationService authentication, RequestTokenResponse response, string clientId, string issuer, string expectedNonce,
                                                               string version, JWKeyset jwks, MobileConnectRequestOptions options)
        {
            if (response.ErrorResponse != null)
            {
                return(MobileConnectStatus.Error(response.ErrorResponse.Error, response.ErrorResponse.ErrorDescription, null, response));
            }

            response.ValidationResult = authentication.ValidateTokenResponse(response, clientId, issuer, expectedNonce, options?.MaxAge, jwks, version);
            var validationOptions = options?.TokenValidationOptions ?? new TokenValidationOptions();

            if (!validationOptions.AcceptedValidationResults.HasFlag(response.ValidationResult))
            {
                Log.Error(() => $"A generated tokenResponse was invalid issuer={issuer} version={version} result={response.ValidationResult}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidToken, $"The token was found to be invalid with the validation result {response.ValidationResult}", null, response));
            }
            else if (response.ValidationResult != TokenValidationResult.Valid)
            {
                Log.Warning(() => $"A generated tokenResponse was invalid but accepted issuer={issuer} version={version} result={response.ValidationResult}");
            }

            return(MobileConnectStatus.Complete(response));
        }
Пример #23
0
        internal static async Task <MobileConnectStatus> AttemptDiscovery(IDiscovery discovery, string msisdn, string mcc, string mnc, IEnumerable <BasicKeyValuePair> cookies, MobileConnectConfig config, MobileConnectRequestOptions options)
        {
            DiscoveryResponse response = null;

            try
            {
                DiscoveryOptions discoveryOptions = options?.DiscoveryOptions ?? new DiscoveryOptions();
                discoveryOptions.MSISDN        = msisdn;
                discoveryOptions.IdentifiedMCC = mcc;
                discoveryOptions.IdentifiedMNC = mnc;
                discoveryOptions.RedirectUrl   = config.RedirectUrl;

                response = await discovery.StartAutomatedOperatorDiscoveryAsync(config, config.RedirectUrl, discoveryOptions, cookies);
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                return(MobileConnectStatus.Error("invalid_argument", string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                return(MobileConnectStatus.Error("http_failure", "An HTTP failure occured while calling the discovery endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                return(MobileConnectStatus.Error("unknown_error", "An unknown error occured while calling the Discovery service to obtain operator details", e));
            }

            return(GenerateStatusFromDiscoveryResponse(discovery, response));
        }
Пример #24
0
 /// <summary>
 /// Syncronous wrapper for <see cref="RequestPremiumInfoAsync"/>
 /// </summary>
 /// <param name="discoveryResponse">The response returned by the discovery process</param>
 /// <param name="accessToken">Access token from RequestToken stage</param>
 /// <param name="options">Additional optional parameters</param>
 /// <returns>MobileConnectStatus object with UserInfo information</returns>
 public MobileConnectStatus RequestPremiumInfo(
     DiscoveryResponse discoveryResponse, string accessToken, MobileConnectRequestOptions options)
 {
     return(MobileConnectInterfaceHelper.RequestPremiumInfo(
                _identity, discoveryResponse, accessToken, _config, options).Result);
 }
Пример #25
0
 /// <summary>
 /// Attempt discovery using the supplied parameters. If msisdn, mcc and mnc are null the result will be
 /// operator selection, otherwise valid parameters will result in a StartAuthorization status
 /// </summary>
 /// <param name="msisdn">MSISDN from user</param>
 /// <param name="mcc">Mobile Country Code</param>
 /// <param name="mnc">Mobile Network Code</param>
 /// <param name="options">Optional parameters</param>
 /// <returns>MobileConnectStatus object with required information for continuing the mobileconnect process</returns>
 public async Task <MobileConnectStatus> AttemptDiscoveryAsync(
     string msisdn, string mcc, string mnc, MobileConnectRequestOptions options)
 {
     return(await MobileConnectInterfaceHelper.AttemptDiscovery(
                _discovery, msisdn, mcc, mnc, null, _config, options));
 }
        internal static async Task <MobileConnectStatus> RequestHeadlessAuthentication(IAuthenticationService authentication, IJWKeysetService jwks, IIdentityService identity, DiscoveryResponse discoveryResponse, string encryptedMSISDN,
                                                                                       string state, string nonce, MobileConnectConfig config, MobileConnectRequestOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!IsUsableDiscoveryResponse(discoveryResponse))
            {
                return(MobileConnectStatus.StartDiscovery());
            }

            MobileConnectStatus status;

            try
            {
                string                clientId          = discoveryResponse.ResponseData.response.client_id ?? config.ClientId;
                string                clientSecret      = discoveryResponse.ResponseData.response.client_secret;
                string                authorizationUrl  = discoveryResponse.OperatorUrls.AuthorizationUrl;
                string                tokenUrl          = discoveryResponse.OperatorUrls.RequestTokenUrl;
                string                issuer            = discoveryResponse.ProviderMetadata.Issuer;
                SupportedVersions     supportedVersions = discoveryResponse.ProviderMetadata.MobileConnectVersionSupported;
                AuthenticationOptions authOptions       = options?.AuthenticationOptions ?? new AuthenticationOptions();
                authOptions.ClientName = discoveryResponse.ApplicationShortName;

                var jwksTask  = jwks.RetrieveJWKSAsync(discoveryResponse.OperatorUrls.JWKSUrl);
                var tokenTask = authentication.RequestHeadlessAuthentication(clientId, clientSecret, authorizationUrl, tokenUrl, config.RedirectUrl, state, nonce,
                                                                             encryptedMSISDN, supportedVersions, authOptions, cancellationToken);

                // execute both tasks in parallel
                await Task.WhenAll(tokenTask, jwksTask).ConfigureAwait(false);

                RequestTokenResponse response = tokenTask.Result;

                status = HandleTokenResponse(authentication, response, clientId, issuer, nonce,
                                             discoveryResponse.ProviderMetadata.MobileConnectVersionSupported.MaxSupportedVersionString, jwksTask.Result, options);
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to RequestHeadlessAuthentication arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                Log.Error(() => $"A general http error occurred in RequestHeadlessAuthentication state={state} nonce={nonce} authUrl={discoveryResponse.OperatorUrls.AuthorizationUrl} tokenUrl={discoveryResponse.OperatorUrls.RequestTokenUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.HttpFailure, "An HTTP failure occured while calling the discovery endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in RequestHeadlessAuthentication state={state} nonce={nonce} authUrl={discoveryResponse.OperatorUrls.AuthorizationUrl} tokenUrl={discoveryResponse.OperatorUrls.RequestTokenUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "An unknown error occured while generating an authorization url", e));
            }

            if (status.ResponseType == MobileConnectResponseType.Error ||
                !options.AutoRetrieveIdentityHeadless || string.IsNullOrEmpty(discoveryResponse.OperatorUrls.PremiumInfoUrl))
            {
                return(status);
            }

            var identityStatus = await RequestIdentity(identity, discoveryResponse, status.TokenResponse.ResponseData.AccessToken, config, options);

            status.IdentityResponse = identityStatus.IdentityResponse;

            return(status);
        }
Пример #27
0
        internal static MobileConnectStatus StartAuthorization(IAuthentication authentication, DiscoveryResponse discoveryResponse, string encryptedMSISDN, string state, string nonce, MobileConnectConfig config, MobileConnectRequestOptions options)
        {
            StartAuthenticationResponse response;

            try
            {
                string clientId         = discoveryResponse?.ResponseData?.response?.client_id ?? config.ClientId;
                string authorizationUrl = discoveryResponse?.OperatorUrls?.AuthorizationUrl;
                response = authentication.StartAuthentication(clientId, authorizationUrl, config.RedirectUrl, state, nonce, config.AuthorizationScope, config.AuthorizationMaxAge, config.AuthorizationAcrValues, encryptedMSISDN, options?.AuthenticationOptions);
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                return(MobileConnectStatus.Error("invalid_argument", string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (Exception e)
            {
                return(MobileConnectStatus.Error("unknown_error", "An unknown error occured while generating an authorization url", e));
            }

            return(MobileConnectStatus.Authorization(response.Url, state, nonce));
        }
        internal static async Task <MobileConnectStatus> RequestToken(IAuthenticationService authentication, IJWKeysetService jwks, DiscoveryResponse discoveryResponse, Uri redirectedUrl, string expectedState,
                                                                      string expectedNonce, MobileConnectConfig config, MobileConnectRequestOptions options)
        {
            RequestTokenResponse response;

            if (!IsUsableDiscoveryResponse(discoveryResponse))
            {
                return(MobileConnectStatus.StartDiscovery());
            }

            if (string.IsNullOrEmpty(expectedState))
            {
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, "ExpectedState argument was not supplied, this is needed to prevent Cross-Site Request Forgery", null));
            }

            if (string.IsNullOrEmpty(expectedNonce))
            {
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, "expectedNonce argument was not supplied, this is needed to prevent Replay Attacks", null));
            }

            var actualState = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "state");

            if (expectedState != actualState)
            {
                return(MobileConnectStatus.Error(ErrorCodes.InvalidState, "State values do not match, this could suggest an attempted Cross-Site Request Forgery", null));
            }

            try
            {
                var code            = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "code");
                var clientId        = discoveryResponse.ResponseData.response.client_id ?? config.ClientId;
                var clientSecret    = discoveryResponse.ResponseData.response.client_secret ?? config.ClientSecret;
                var requestTokenUrl = discoveryResponse.OperatorUrls.RequestTokenUrl;
                var issuer          = discoveryResponse.ProviderMetadata.Issuer;

                var tokenTask = authentication.RequestTokenAsync(clientId, clientSecret, requestTokenUrl, config.RedirectUrl, code);
                var jwksTask  = jwks.RetrieveJWKSAsync(discoveryResponse.OperatorUrls.JWKSUrl);

                // execute both tasks in parallel
                await Task.WhenAll(tokenTask, jwksTask).ConfigureAwait(false);

                response = tokenTask.Result;

                var maxSupportedVersion = discoveryResponse.ProviderMetadata?.MobileConnectVersionSupported == null ? "mc_v1.1" : discoveryResponse.ProviderMetadata.MobileConnectVersionSupported.MaxSupportedVersionString;

                return(HandleTokenResponse(authentication, response, clientId, issuer, expectedNonce,
                                           maxSupportedVersion, jwksTask.Result, options));
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                Log.Error(() => $"An invalid argument was passed to RequestToken arg={e.Argument}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidArgument, string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                Log.Error(() => $"A general http error occurred in RequestToken redirectedUrl={redirectedUrl} requestTokenUrl={discoveryResponse.OperatorUrls.RequestTokenUrl} jwksUrl={discoveryResponse.OperatorUrls.JWKSUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.HttpFailure, "An HTTP failure occured while calling the operator token endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                Log.Error(() => $"A general error occurred in RequestToken redirectedUrl={redirectedUrl} requestTokenUrl={discoveryResponse.OperatorUrls.RequestTokenUrl} jwksUrl={discoveryResponse.OperatorUrls.JWKSUrl}");
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "A failure occured while requesting a token", e));
            }
        }