Esempio n. 1
0
        public static IOAuthOpenIdToken NewOpenIdToken(this IOAuthAccessToken accessToken, OpenIdToken idToken, string json)
        {
            var session = EntityHelper.GetSession(accessToken);
            var tknEnt  = accessToken.OpenIdToken = session.NewEntity <IOAuthOpenIdToken>();

            tknEnt.Issuer         = idToken.Issuer;
            tknEnt.AuthContextRef = idToken.ContextRef;
            tknEnt.Subject        = idToken.Subject;
            tknEnt.Audience       = idToken.Audience;
            tknEnt.IssuedAt       = OpenIdConnectUtil.FromUnixTime(idToken.IssuedAt);
            tknEnt.ExpiresAt      = OpenIdConnectUtil.FromUnixTime(idToken.ExpiresAt);
            if (idToken.AuthTime > 0)
            {
                tknEnt.AuthTime = OpenIdConnectUtil.FromUnixTime(idToken.AuthTime);
            }
            tknEnt.FullJson = json;
            return(tknEnt);
        }
        public async Task <Guid> RetrieveAccessTokenAsync(OperationContext context, Guid flowId)
        {
            var session = context.OpenSystemSession();
            var flow    = session.GetEntity <IOAuthClientFlow>(flowId);

            Util.Check(flow != null, "OAuth client flow not found, ID: {0}", flowId);
            ThrowIfExpired(flow);
            string err = null;

            switch (flow.Status)
            {
            case OAuthFlowStatus.Started: err = "Access not authorized yet."; break;

            case OAuthFlowStatus.TokenRetrieved: err = "Authorization code already used to retrieve token."; break;

            case OAuthFlowStatus.Error: err = "Authorization failed or denied - " + flow.Error; break;
            }
            Util.Check(err == null, "Cannot retrieve token: {0}.", err);
            Util.CheckNotEmpty(flow.AuthorizationCode, "Authorization code not retrieved, cannot retrieve access token.");

            var apiClient     = new WebApiClient(context, flow.Account.Server.TokenRequestUrl, ClientOptions.Default, badRequestContentType: typeof(string));
            var clientSecret  = flow.Account.ClientSecret;
            var server        = flow.Account.Server;
            var serverOptions = server.Options;
            // Some servers expect clientId/secret in Authorization header
            string query;

            if (serverOptions.IsSet(OAuthServerOptions.ClientInfoInAuthHeader))
            {
                AddClientInfoHeader(apiClient, flow.Account.ClientIdentifier, clientSecret);
                query = StringHelper.FormatUri(AccessTokenUrlQueryTemplate, flow.AuthorizationCode, flow.RedirectUrl);
            }
            else
            {
                //others - clientId/secret mixed with other parameters
                query = StringHelper.FormatUri(AccessTokenUrlQueryTemplateWithClientInfo, flow.AuthorizationCode,
                                               flow.RedirectUrl, flow.Account.ClientIdentifier, clientSecret);
            }

            query = StringHelper.FormatUri(AccessTokenUrlQueryTemplateWithClientInfo, flow.AuthorizationCode,
                                           flow.RedirectUrl, flow.Account.ClientIdentifier, clientSecret);


            //Make a call; standard is POST, but some servers use GET (LinkedIn)
            AccessTokenResponse tokenResp;

            if (serverOptions.IsSet(OAuthServerOptions.TokenUseGet))
            {
                //GET, no body
                tokenResp = await apiClient.GetAsync <AccessTokenResponse>("?" + query);
            }
            else
            {
                var formContent = CreateFormUrlEncodedContent(query);
                tokenResp = await apiClient.PostAsync <HttpContent, AccessTokenResponse>(formContent, string.Empty);
            }
            flow.Status = OAuthFlowStatus.TokenRetrieved;
            //LinkedIn returns milliseconds here - it's a bug, reported. So here is workaround
            var expIn = tokenResp.ExpiresIn;

            if (expIn > 1e+9) //if more than one billion, it is milliseconds
            {
                expIn = expIn / 1000;
            }
            var            expires = this.App.TimeService.UtcNow.AddSeconds(expIn);
            OAuthTokenType tokenType;
            var            ok = Enum.TryParse <OAuthTokenType>(tokenResp.TokenType, true, out tokenType); //should be Bearer
            // Create AccessToken entity
            var accessToken = flow.Account.NewOAuthAccessToken(flow.UserId, tokenResp.AccessToken, tokenType,
                                                               tokenResp.RefreshToken, tokenResp.IdToken, flow.Scopes, App.TimeService.UtcNow, expires, Settings.EncryptionChannel);

            // Unpack OpenId id_token - it is JWT token
            if (serverOptions.IsSet(OAuthServerOptions.OpenIdConnect) && !string.IsNullOrWhiteSpace(tokenResp.IdToken))
            {
                var payload = OpenIdConnectUtil.GetJwtPayload(tokenResp.IdToken);
                var idTkn   = Settings.JsonDeserializer.Deserialize <OpenIdToken>(payload);
                accessToken.NewOpenIdToken(idTkn, payload);
            }
            session.SaveChanges();
            Authorized?.Invoke(this, new OAuthClient.OAuthEventArgs(context, flow.Id));
            return(accessToken.Id);
        }