diff --git a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/IOidcProvider.cs b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/IOidcProvider.cs index 29511d23..5787373d 100644 --- a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/IOidcProvider.cs +++ b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/IOidcProvider.cs @@ -55,6 +55,14 @@ public interface IOidcProvider /// Returns the access token if it could be retrieved; otherwise it returns an empty string Task GetAccessTokenFromCodeAsync(string code, string redirectUri); + /// + /// Gets the complete authorization answer from the selected provider + /// + /// The authorization code + /// The redirect URI which was used during the login + /// Returns the complete authorization answer + Task GetAuthorizationAnswerAsync(string code, string redirectUri); + /// /// Gets the access token from a list of parameters in a Web answer /// diff --git a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Abstract Provider/AbstractOIDCProvider.cs b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Abstract Provider/AbstractOIDCProvider.cs index 5a7b7f1d..4d006a2e 100644 --- a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Abstract Provider/AbstractOIDCProvider.cs +++ b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Abstract Provider/AbstractOIDCProvider.cs @@ -195,6 +195,45 @@ public virtual async Task GetAccessTokenFromCodeAsync(string code, strin } } + public virtual async Task GetAuthorizationAnswerAsync(string code, string redirectUri) + { + if (ClientData == null) + { + i5Debug.LogError("No client data supplied for the OpenID Connect Client.\n" + + "Initialize this provider with an OpenID Connect Data file.", this); + return null; + } + + WWWForm form = new WWWForm(); + form.AddField("client_id", ClientData.ClientId); + form.AddField("client_secret", ClientData.ClientSecret); + form.AddField("grant_type", "authorization_code"); + form.AddField("redirect_uri", redirectUri); + form.AddField("code", code); + + Dictionary headers = new Dictionary() + { + { "Content-Type", "application/x-www-form-urlencoded" } + }; + WebResponse response = await RestConnector.PostAsync(tokenEndpoint, form.data, headers); + if (response.Successful) + { + AbstractAuthorizationFlowAnswer answer = + JsonSerializer.FromJson(response.Content); + if (answer == null) + { + i5Debug.LogError("Could not parse access token in code flow answer", this); + return null; + } + return answer; + } + else + { + Debug.LogError(response.ErrorMessage + ": " + response.Content); + return null; + } + } + /// /// Gets the access token from a list of parameters in a Web answer /// diff --git a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs index 9209dbc8..1b032e06 100644 --- a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs +++ b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs @@ -62,6 +62,38 @@ public override async Task GetAccessTokenFromCodeAsync(string code, stri } } + public override async Task GetAuthorizationAnswerAsync(string code, string redirectUri) + { + if (ClientData == null) + { + i5Debug.LogError("No client data supplied for the OpenID Connect Client.\n" + + "Initialize this provider with an OpenID Connect Data file.", this); + return null; + } + + string uri = tokenEndpoint + $"?client_id={ClientData.ClientId}" + + $"&redirect_uri={redirectUri}" + $"&client_secret={ClientData.ClientSecret}&code={code}&grant_type=authorization_code"; + WebResponse response = await RestConnector.PostAsync(uri, ""); + + if (response.Successful) + { + string response_content = response.Content; + GitHubAuthorizationFlowAnswer answer = + JsonSerializer.FromJson(response_content); + if (answer == null) + { + i5Debug.LogError("Could not parse access token in code flow answer", this); + return null; + } + return answer; + } + else + { + i5Debug.LogError(response.ErrorMessage + ": " + response.Content, this); + return null; + } + } + /// /// Gets information about the logged in user from the GitHub provider /// diff --git a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Google/GoogleOIDCProvider.cs b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Google/GoogleOIDCProvider.cs index d34d4f25..820b653a 100644 --- a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Google/GoogleOIDCProvider.cs +++ b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OIDC Providers/Google/GoogleOIDCProvider.cs @@ -60,9 +60,7 @@ public void GenerateCSRFToken() /// Returns the access token if it could be retrieved; otherwise it returns an empty string public override async Task GetAccessTokenFromCodeAsync(string code, string redirectUri) { - redirectUri += "code?"; - - EndpointsData endpoints = await InitializeEndpointsAsync(); + await InitializeEndpointsAsync(); if (ClientData == null) { i5Debug.LogError("No client data supplied for the OpenID Connect Client.\n" + @@ -100,6 +98,46 @@ public override async Task GetAccessTokenFromCodeAsync(string code, stri } } + public override async Task GetAuthorizationAnswerAsync(string code, string redirectUri) + { + await InitializeEndpointsAsync(); + if (ClientData == null) + { + i5Debug.LogError("No client data supplied for the OpenID Connect Client.\n" + + "Initialize this provider with an OpenID Connect Data file.", this); + return null; + } + + WWWForm form = new WWWForm(); + form.AddField("code", code); + form.AddField("client_id", ClientData.ClientId); + form.AddField("client_secret", ClientData.ClientSecret); + form.AddField("redirect_uri", redirectUri); + form.AddField("grant_type", "authorization_code"); + + Dictionary headers = new Dictionary() + { + { "Content-Type", "application/x-www-form-urlencoded" } + }; + WebResponse response = await RestConnector.PostAsync(tokenEndpoint, form.data, headers); + if (response.Successful) + { + GoogleAuthorizationFlowAnswer answer = + JsonSerializer.FromJson(response.Content); + if (answer == null) + { + i5Debug.LogError("Could not parse access token in code flow answer", this); + return null; + } + return answer; + } + else + { + i5Debug.LogError(response.ErrorMessage + ": " + response.Content, this); + return null; + } + } + /// /// Extracts the authorization code from parameters of a Web answer /// @@ -136,7 +174,6 @@ public override void OpenLoginPage(string[] scopes, string redirectUri) GenerateCSRFToken(); string responseType = AuthorizationFlow == AuthorizationFlow.AUTHORIZATION_CODE ? "code" : "token"; string uriScopes = UriUtils.WordArrayToSpaceEscapedString(scopes); - redirectUri += "code?"; string uri = authorizationEndpoint + $"?client_id={ClientData.ClientId}" + $"&response_type={responseType}" + $"&redirect_uri={redirectUri}" + $"&scope={uriScopes}" + $"&state={state}"; Browser.OpenURL(uri); diff --git a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OpenIDConnectService.cs b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OpenIDConnectService.cs index a0dbc7be..509445d3 100644 --- a/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OpenIDConnectService.cs +++ b/Assets/i5 Toolkit for Unity/Runtime/OpenID Connect/Scripts/OpenIDConnectService.cs @@ -30,6 +30,8 @@ public class OpenIDConnectService : IUpdateableService /// public string AccessToken { get; private set; } + private AbstractAuthorizationFlowAnswer _authorizationAnswer; + /// /// Is true if the user of the application is currently logged in /// @@ -62,7 +64,7 @@ public class OpenIDConnectService : IUpdateableService /// /// Event which is raised once the login was successfully completed /// - public event EventHandler LoginCompleted; + public event EventHandler LoginCompleted; /// /// Event which is reaised once the logout was completed /// @@ -267,16 +269,18 @@ public async void Update() if (OidcProvider.AuthorizationFlow == AuthorizationFlow.AUTHORIZATION_CODE) { string authorizationCode = OidcProvider.GetAuthorizationCode(eventArgs.RedirectParameters); - AccessToken = await OidcProvider.GetAccessTokenFromCodeAsync(authorizationCode, eventArgs.RedirectUri); + _authorizationAnswer = await OidcProvider.GetAuthorizationAnswerAsync(authorizationCode, eventArgs.RedirectUri); + AccessToken = _authorizationAnswer.access_token; } else { AccessToken = OidcProvider.GetAccessToken(eventArgs.RedirectParameters); + _authorizationAnswer = new AbstractAuthorizationFlowAnswer() { access_token = AccessToken}; } eventArgs = null; - if (!string.IsNullOrEmpty(AccessToken)) + if (_authorizationAnswer != null) { - LoginCompleted?.Invoke(this, EventArgs.Empty); + LoginCompleted?.Invoke(this, _authorizationAnswer); } else {