diff --git a/CHANGELOG.md b/CHANGELOG.md index 14939cbf..d14672ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ This document keeps track of the changes between versions of the toolkit. +## 1.4.0 (2021-03-28) + +### Added +- Added support for GitHub OpenID Connect login +- Added an option to the `IRestConnector` interface methods to specify a header dictionary +- Added an option to the `UnityWebRestConnector` to process a supplied header dictionary +- Added an example for the GitHub OpenID Connect login +- Added an example that shows how to use multiple OpenID Connect providers in parallel + ## 1.3.4 (2021-03-18) ### Changed diff --git a/Documentation~/i5-Toolkit-for-Unity.md b/Documentation~/i5-Toolkit-for-Unity.md index 02e92b69..80f3a436 100644 --- a/Documentation~/i5-Toolkit-for-Unity.md +++ b/Documentation~/i5-Toolkit-for-Unity.md @@ -1,3 +1,3 @@ # Documentation of the i5 Toolkit for Unity -Click [here](https://rwth-acis.github.io/i5-Toolkit-for-Unity/1.3.4/index.html) to go to the documentation pages for version 1.3.4 of the package. \ No newline at end of file +Click [here](https://rwth-acis.github.io/i5-Toolkit-for-Unity/1.4.0/index.html) to go to the documentation pages for version 1.4.0 of the package. \ No newline at end of file diff --git a/Editor/Scene Documentation/Scripts/SceneDocumentationInitializer.cs b/Editor/Scene Documentation/Scripts/SceneDocumentationInitializer.cs index 2c497bae..5f6b6f88 100644 --- a/Editor/Scene Documentation/Scripts/SceneDocumentationInitializer.cs +++ b/Editor/Scene Documentation/Scripts/SceneDocumentationInitializer.cs @@ -7,42 +7,45 @@ using UnityEditor; using UnityEngine; -/// -/// Initializes the scene documentation resources -/// -[InitializeOnLoad] -public class SceneDocumentationInitializer +namespace i5.Toolkit.Core.SceneDocumentation { /// - /// Static constructor which copies the gizmos files from the textures folder to the Assets/Gizmos folder + /// Initializes the scene documentation resources /// - static SceneDocumentationInitializer() + [InitializeOnLoad] + public class SceneDocumentationInitializer { - if (!Directory.Exists("Assets/Gizmos")) + /// + /// Static constructor which copies the gizmos files from the textures folder to the Assets/Gizmos folder + /// + static SceneDocumentationInitializer() { - Directory.CreateDirectory("Assets/Gizmos"); - Debug.Log("[SceneDocumentationInitializer] Created Gizmos folder"); - } + if (!Directory.Exists("Assets/Gizmos")) + { + Directory.CreateDirectory("Assets/Gizmos"); + Debug.Log("[SceneDocumentationInitializer] Created Gizmos folder"); + } - string packageLocation = PathUtils.GetPackagePath(); + string packageLocation = PathUtils.GetPackagePath(); - EnsureFile(packageLocation, "Bug.png"); - EnsureFile(packageLocation, "Todo.png"); - EnsureFile(packageLocation, "Info.png"); - } + EnsureFile(packageLocation, "Bug.png"); + EnsureFile(packageLocation, "Todo.png"); + EnsureFile(packageLocation, "Info.png"); + } - /// - /// Ensures that the file with the given name exists in the Gizmos folder - /// If it does not exist, it is copied from the textures folder - /// - /// The path where the package is located in the project - /// The filename of the gizmos icon - private static void EnsureFile(string packageLocation, string filename) - { - if (!File.Exists("Assets/Gizmos/" + filename)) + /// + /// Ensures that the file with the given name exists in the Gizmos folder + /// If it does not exist, it is copied from the textures folder + /// + /// The path where the package is located in the project + /// The filename of the gizmos icon + private static void EnsureFile(string packageLocation, string filename) { - File.Copy(packageLocation + "Editor/Scene Documentation/Textures/" + filename, "Assets/Gizmos/" + filename); - Debug.Log("[SceneDocumentationInitializer] Copied " + filename + " to Gizmos folder"); + if (!File.Exists("Assets/Gizmos/" + filename)) + { + File.Copy(packageLocation + "Editor/Scene Documentation/Textures/" + filename, "Assets/Gizmos/" + filename); + Debug.Log("[SceneDocumentationInitializer] Copied " + filename + " to Gizmos folder"); + } } } } diff --git a/README.md b/README.md index 54726864..52237efb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ It is a foundation for new projects, kickstarting the development with already c ![Continuous Integration](https://github.com/rwth-acis/i5-Toolkit-for-Unity/workflows/Continuous%20Integration/badge.svg) -![1.3.4](https://img.shields.io/badge/version-1.3.4-blue) +![1.4.0](https://img.shields.io/badge/version-1.4.0-blue) [![openupm](https://img.shields.io/npm/v/com.i5.toolkit.core?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.i5.toolkit.core/) @@ -17,22 +17,22 @@ The i5 Toolkit provides a series of modules and features that can be used in pro - - - + + + - - - + + + - - - + + + - +
App Console
App Console
Modified 3D Objects
Modified 3D Models
Object Pool
Object Pool
App Console
App Console
Modified 3D Objects
Modified 3D Models
Object Pool
Object Pool
Obj Importer
Obj Importer
OpenID Connect Client
OpenID Connect Client
Procedural Geometry
Procedural Geometry
Obj Importer
Obj Importer
OpenID Connect Client
OpenID Connect Client
Procedural Geometry
Procedural Geometry
Scene Documentation
Scene Documentation
Service Core
Service Core
Spawner
Spawner
Scene Documentation
Scene Documentation
Service Core
Service Core
Spawner
Spawner
Version Tool
Version Tool
Version Tool
Version Tool
@@ -59,7 +59,7 @@ To do this, add an entry to the dependency file: } ``` -4. To add a specific version of the tool to the dependencies, add the following line inside of the "dependencies" object and replace [version] by the release number, e.g. "1.3.4". +4. To add a specific version of the tool to the dependencies, add the following line inside of the "dependencies" object and replace [version] by the release number, e.g. "1.4.0". `"com.i5.toolkit.core": "[version]",` After that, Unity will automatically download and import the package. @@ -78,7 +78,7 @@ So, after completing these steps you should have a manifest.json file which look ... some more scoped registries ], "dependencies": { - "com.i5.toolkit.core": "1.3.4", + "com.i5.toolkit.core": "1.4.0", ... some more packages } } @@ -92,7 +92,7 @@ It can be included in new projects by referencing the git-repository on GitHub i 1. Open your project's root folder in a file explorer. 2. Navigate to the Packages folder and open the file manifest.json. It contains a list of package dependencies which are loaded into the project. -3. To add a specific version of the tool to the dependencies, add the following line inside of the "dependencies" object and replace [version] with "v", followed by the release number, e.g. "v1.3.4". +3. To add a specific version of the tool to the dependencies, add the following line inside of the "dependencies" object and replace [version] with "v", followed by the release number, e.g. "v1.4.0". To receive the latest version, replace [version] with upm. `"com.i5.toolkit.core": "https://github.com/rwth-acis/i5-Toolkit-for-Unity.git#[version]",` After that, Unity will automatically download and import the package. @@ -107,7 +107,7 @@ The package can be downloaded from a git-repository in the package manager's UI. 1. In Unity, go to Window > Package Manger. 2. Click on the plus-button in the top left corner of the package manager and select "add". -3. Enter https://github.com/rwth-acis/i5-Toolkit-for-Unity.git#[version] into the text field where [version] is replaced with "v", followed by the release number, e.g. "v1.3.4" or upm for the latest version. +3. Enter https://github.com/rwth-acis/i5-Toolkit-for-Unity.git#[version] into the text field where [version] is replaced with "v", followed by the release number, e.g. "v1.4.0" or upm for the latest version. Confirm the download by clicking on the "add" button. If you specify "upm" to get the latest version, be aware that the package is not automatically updated. diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub.meta b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub.meta new file mode 100644 index 00000000..c2eaa9fe --- /dev/null +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ccf32ffc2b051ec489a325381a5889a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs new file mode 100644 index 00000000..4b0375c1 --- /dev/null +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs @@ -0,0 +1,17 @@ +using System; + +namespace i5.Toolkit.Core.OpenIDConnectClient +{ + /// + /// Data description of the answer that is received after the access token was requested in the + /// authorization flow + /// + [Serializable] + public class GitHubAuthorizationFlowAnswer + { + public string access_token; + public string scope; + public string token_type; + + } +} diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs.meta b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs.meta new file mode 100644 index 00000000..3f627d53 --- /dev/null +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubAuthorizationFlowAnswer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3046395fc09c0340ac315dba7de9c43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs new file mode 100644 index 00000000..a1a6474c --- /dev/null +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubOIDCProvider.cs @@ -0,0 +1,231 @@ +using i5.Toolkit.Core.Utilities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEngine; + +namespace i5.Toolkit.Core.OpenIDConnectClient +{ + /// + /// Implementation of the OpenID Connect GitHub Provider + /// + public class GitHubOidcProvider : IOidcProvider + { + /// + /// The endpoint for the log in + /// + private const string authorizationEndpoint = "https://github.com/login/oauth/authorize"; + /// + /// The end point where the access token can be requested + /// + private const string tokenEndpoint = "https://github.com/login/oauth/access_token"; + /// + /// The end point where user information can be requested + /// + private const string userInfoEndpoint = "https://api.github.com/user"; + + /// + /// Gets or sets the used authorization flow + /// + public AuthorizationFlow AuthorizationFlow { get; set; } + + /// + /// Specifies how the REST API of the Web service is accessed + /// + public IRestConnector RestConnector { get; set; } + + /// + /// Client data that are required to authorize the client at the provider + /// + public ClientData ClientData { get; set; } + + /// + /// Serializer that is responsible for parsing JSON data and converting to JSON + /// + public IJsonSerializer JsonSerializer { get; set; } + + /// + /// The implementation that should accesss the browser + /// + public IBrowser Browser { get; set; } + + /// + /// Creates a new instance of the GitHub client + /// + public GitHubOidcProvider() + { + RestConnector = new UnityWebRequestRestConnector(); + JsonSerializer = new JsonUtilityWrapper(); + Browser = new Browser(); + } + + /// + /// Gets the access token based on a previously retrieved authorization code + /// + /// The authorization code + /// The redirect URI which was used during the login + /// Returns the access token if it could be retrieved; otherwise it returns an empty string + public async Task GetAccessTokenFromCodeAsync(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 ""; + } + + 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 = WrapAsJson(response.Content); + GitHubAuthorizationFlowAnswer answer = + JsonSerializer.FromJson(response_content); + if (answer == null) + { + i5Debug.LogError("Could not parse access token in code flow answer", this); + return ""; + } + return answer.access_token; + } + else + { + Debug.LogError(response.ErrorMessage + ": " + response.Content); + return ""; + } + } + + /// + /// Gets the access token from a list of parameters in a Web answer + /// + /// The parameters of the Web answer as a dictionary + /// Returns the access token if it exists in the parameters, + /// otherwise an empty string is returned + public string GetAccessToken(Dictionary redirectParameters) + { + if (redirectParameters.ContainsKey("token")) + { + return redirectParameters["token"]; + } + else + { + i5Debug.LogError("Redirect parameters did not contain access token", this); + return ""; + } + } + + /// + /// Gets information about the logged in user from the GitHub provider + /// + /// The access token to authenticate the user + /// Returns information about the logged in user if the request was successful, otherwise null + public async Task GetUserInfoAsync(string accessToken) + { + Dictionary headers = new Dictionary(); + headers.Add("Authorization", $"token {accessToken}"); + WebResponse webResponse = await RestConnector.GetAsync(userInfoEndpoint + "?access_token=" + accessToken, headers); + if (webResponse.Successful) + { + GitHubUserInfo userInfo = JsonSerializer.FromJson(webResponse.Content); + if (userInfo == null) + { + i5Debug.LogError("Could not parse user info", this); + } + return userInfo; + } + else + { + i5Debug.LogError("Error fetching the user info: " + webResponse.ErrorMessage, this); + return default; + } + } + + /// + /// Checks if the access token is valid by checking it at the GitHub provider + /// + /// The access token that should be checked + /// True if the access token is valid, otherwise false + public async Task CheckAccessTokenAsync(string accessToken) + { + IUserInfo userInfo = await GetUserInfoAsync(accessToken); + return userInfo != null; + } + + /// + /// Opens the GitHUb login page in the system's default Web browser + /// + /// The OpenID Connect scopes that the user must agree to + /// The URI to which the browser should redirect after the successful login + public void OpenLoginPage(string[] scopes, 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; + } + + string responseType = AuthorizationFlow == AuthorizationFlow.AUTHORIZATION_CODE ? "code" : "token"; + string uriScopes = UriUtils.WordArrayToSpaceEscapedString(scopes); + string uri = authorizationEndpoint + $"?client_id={ClientData.ClientId}&redirect_uri={redirectUri}" + $"response_type={responseType}&scope={uriScopes}"; + Browser.OpenURL(uri); + } + + /// + /// Extracts the authorization code from parameters of a Web answer + /// + /// Parameters of a Web answer as a dictionary + /// The authorization code if it could be found, otherwise an empty string is returned + public string GetAuthorizationCode(Dictionary redirectParameters) + { + if (redirectParameters.ContainsKey("code")) + { + return redirectParameters["code"]; + } + else + { + i5Debug.LogError("Redirect parameters did not contain authorization code", this); + return ""; + } + } + + /// + /// Checks if the provider included error messages in the parameters of a Web answer + /// + /// The parameters of a Web answer as a dictionary + /// The error message that the provider included, empty if no error exists + /// Returns true if the parameters contain an error message, otherwise false + public bool ParametersContainError(Dictionary parameters, out string errorMessage) + { + if (parameters.ContainsKey("error")) + { + errorMessage = parameters["error"]; + return true; + } + errorMessage = ""; + return false; + } + + private string WrapAsJson(string token) + { + string[] parameters = token.Split('&', '='); + string wrappedToken = "{"; + for(int i=0; i + /// Description of the user information data for the Git Hub client + /// + public class GitHubUserInfo : IUserInfo + { + [SerializeField] private string login; + [SerializeField] private string email; + + /// + /// The username of the user + /// This is a mapping based on the available user data of the OIDC provider + /// + public string Username { get => login; } + + /// + /// The email address of the user + /// This is a mapping based on the available user data of the OIDC provider + /// + public string Email { get => email; } + + /// + /// A clear name of the user + /// This is a mapping based on the available user data of the OIDC provider + /// + public string FullName { get => login; } + + /// + /// Creates a new instance of the GitHub user info with the given parameters + /// + /// The user name of the user + /// The email address of the user + /// The full name of the user + public GitHubUserInfo(string loginName, string email) + { + this.login = loginName; + this.email = email; + } + } +} diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubUserInfo.cs.meta b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubUserInfo.cs.meta new file mode 100644 index 00000000..1b0e6f99 --- /dev/null +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Git Hub/GitHubUserInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9038d1343e23e14db4107d038439ffd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/OpenID Connect/Scripts/OIDC Providers/Learning Layers/LearningLayersOIDCProvider.cs.meta b/Runtime/OpenID Connect/Scripts/OIDC Providers/Learning Layers/LearningLayersOIDCProvider.cs.meta index 3b83130a..9f5e13f2 100644 --- a/Runtime/OpenID Connect/Scripts/OIDC Providers/Learning Layers/LearningLayersOIDCProvider.cs.meta +++ b/Runtime/OpenID Connect/Scripts/OIDC Providers/Learning Layers/LearningLayersOIDCProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0a12a48583ed0c94f933c83c988b57b4 +guid: 66d1ac6ea2acc7d45ab835658f7f0416 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Scene Documentation/Scripts/DocumentationObject.cs b/Runtime/Scene Documentation/Scripts/DocumentationObject.cs index fe2f857b..5afc0128 100644 --- a/Runtime/Scene Documentation/Scripts/DocumentationObject.cs +++ b/Runtime/Scene Documentation/Scripts/DocumentationObject.cs @@ -1,37 +1,37 @@ -using UnityEngine; - -namespace i5.Toolkit.Core.SceneDocumentation -{ +using UnityEngine; + +namespace i5.Toolkit.Core.SceneDocumentation +{ /// /// A special component which provides documentation information in the editor - /// - public class DocumentationObject : MonoBehaviour + /// + public class DocumentationObject : MonoBehaviour { /// /// The title of the documentation - /// - public string title; + /// + public string title; /// /// A description of the documented highlight - /// - [TextArea(3, 15)] - public string description; + /// + [TextArea(3, 15)] + public string description; /// /// The type of documentation (e.g. information, todo mark or bug mark) /// Based on this, the icon is changed - /// - public DocumentationType type; + /// + public DocumentationType type; /// /// A url to further documentation on the matter - /// + /// public string url; -#if UNITY_EDITOR +#if UNITY_EDITOR /// /// Called by the Unity Editor to draw gizmos /// Shows the corresponding icon at the position of the Transform - /// + /// private void OnDrawGizmos() { switch(type) @@ -47,14 +47,14 @@ private void OnDrawGizmos() break; } } -#endif - } - +#endif + } + /// /// The different types of Documentation which are available - /// + /// public enum DocumentationType { INFO, TODO, BUG, NO_ICON - } + } } \ No newline at end of file diff --git a/Runtime/ServiceCore/Scripts/IServiceManager.cs b/Runtime/ServiceCore/Scripts/IServiceManager.cs index dffbfa2e..213ee8c3 100644 --- a/Runtime/ServiceCore/Scripts/IServiceManager.cs +++ b/Runtime/ServiceCore/Scripts/IServiceManager.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using i5.Toolkit.Core.OpenIDConnectClient; namespace i5.Toolkit.Core.ServiceCore { @@ -11,6 +12,7 @@ namespace i5.Toolkit.Core.ServiceCore /// public interface IServiceManager { + /// /// The runner object which provides MonoBehaviour events to the service manager /// This can also be used by services to access MonoBehaviour functionality, e.g. for running co-routines diff --git a/Runtime/ServiceCore/Scripts/ServiceManager.cs b/Runtime/ServiceCore/Scripts/ServiceManager.cs index 711ff896..00de58e2 100644 --- a/Runtime/ServiceCore/Scripts/ServiceManager.cs +++ b/Runtime/ServiceCore/Scripts/ServiceManager.cs @@ -115,7 +115,7 @@ public void InstRegisterService(T service) where T : IService } /// - /// Removes a service with the given type from the ServiceManager + /// Removes a provider with the given type from the ServiceManager /// /// The type of service public static void RemoveService() where T : IService diff --git a/Runtime/Utilities/Rest Connectors/IRestConnector.cs b/Runtime/Utilities/Rest Connectors/IRestConnector.cs index 89ce53f4..0c74e67d 100644 --- a/Runtime/Utilities/Rest Connectors/IRestConnector.cs +++ b/Runtime/Utilities/Rest Connectors/IRestConnector.cs @@ -1,18 +1,16 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; -using UnityEngine; namespace i5.Toolkit.Core.Utilities { public interface IRestConnector { - Task> GetAsync(string uri); + Task> GetAsync(string uri, Dictionary headers = null); - Task> PostAsync(string uri, string postData); + Task> PostAsync(string uri, string postData, Dictionary headers = null); - Task> PutAsync(string uri, string postData); + Task> PutAsync(string uri, string postData, Dictionary headers = null); - Task> DeleteAsync(string uri); + Task> DeleteAsync(string uri, Dictionary headers = null); } } \ No newline at end of file diff --git a/Runtime/Utilities/Rest Connectors/UnityWebRequestRestConnector.cs b/Runtime/Utilities/Rest Connectors/UnityWebRequestRestConnector.cs index 6e8c5cde..a8cde010 100644 --- a/Runtime/Utilities/Rest Connectors/UnityWebRequestRestConnector.cs +++ b/Runtime/Utilities/Rest Connectors/UnityWebRequestRestConnector.cs @@ -1,4 +1,5 @@ using i5.Toolkit.Core.Utilities.Async; +using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine.Networking; @@ -6,10 +7,11 @@ namespace i5.Toolkit.Core.Utilities { public class UnityWebRequestRestConnector : IRestConnector { - public async Task> DeleteAsync(string uri) + public async Task> DeleteAsync(string uri, Dictionary headers = null) { using (UnityWebRequest req = UnityWebRequest.Delete(uri)) { + AddHeaders(req, headers); await req.SendWebRequest(); if (req.isHttpError || req.isNetworkError) @@ -23,10 +25,11 @@ public async Task> DeleteAsync(string uri) } } - public async Task> GetAsync(string uri) + public async Task> GetAsync(string uri, Dictionary headers = null) { using (UnityWebRequest req = UnityWebRequest.Get(uri)) { + AddHeaders(req, headers); await req.SendWebRequest(); if(req.isHttpError || req.isNetworkError) @@ -40,10 +43,11 @@ public async Task> GetAsync(string uri) } } - public async Task> PostAsync(string uri, string postData) + public async Task> PostAsync(string uri, string postData, Dictionary headers = null) { using (UnityWebRequest req = UnityWebRequest.Post(uri, postData)) { + AddHeaders(req, headers); await req.SendWebRequest(); if (req.isHttpError || req.isNetworkError) @@ -57,10 +61,11 @@ public async Task> PostAsync(string uri, string postData) } } - public async Task> PutAsync(string uri, string postData) + public async Task> PutAsync(string uri, string postData, Dictionary headers = null) { using (UnityWebRequest req = UnityWebRequest.Put(uri, postData)) { + AddHeaders(req, headers); await req.SendWebRequest(); if (req.isHttpError || req.isNetworkError) @@ -73,5 +78,17 @@ public async Task> PutAsync(string uri, string postData) } } } + + private void AddHeaders(UnityWebRequest req, Dictionary headers) + { + if (headers == null) + { + return; + } + foreach(KeyValuePair header in headers) + { + req.SetRequestHeader(header.Key, header.Value); + } + } } } \ No newline at end of file diff --git a/Samples~/OpenID Connect/GitHub.meta b/Samples~/OpenID Connect/GitHub.meta new file mode 100644 index 00000000..1910553c --- /dev/null +++ b/Samples~/OpenID Connect/GitHub.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 35dbdb55f55be0647bfa9ff1c98b20d6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs b/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs new file mode 100644 index 00000000..a38326b3 --- /dev/null +++ b/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs @@ -0,0 +1,41 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using i5.Toolkit.Core.ServiceCore; +using i5.Toolkit.Core.OpenIDConnectClient; + +namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +{ + public class GitHubOIDCBootstrapper : BaseServiceBootstrapper + { + [SerializeField] private ClientDataObject deepLinkClient; + [SerializeField] private ClientDataObject serverClient; + + protected override void RegisterServices() + { + OpenIDConnectService gitHubOidc = new OpenIDConnectService(); + gitHubOidc.OidcProvider = new GitHubOidcProvider(); + // this example shows how the service can be used on an app for multiple platforms +#if !UNITY_EDITOR + gitHubOidc.RedirectURI = "i5:/"; +#else + gitHubOidc.RedirectURI = "https://www.google.com"; +#endif + +// GitHub only allows one redirect URI per client in its client registration +// therefore, you need to create multiple ones if you need deep linking and the server redirect +// this example also shows how to already set up the client data +#if !UNITY_EDITOR + gitHubOidc.OidcProvider.ClientData = deepLinkClient.clientData; +#else + gitHubOidc.OidcProvider.ClientData = serverClient.clientData; +#endif + + ServiceManager.RegisterService(gitHubOidc); + } + + protected override void UnRegisterServices() + { + } + } +} \ No newline at end of file diff --git a/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs.meta b/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs.meta new file mode 100644 index 00000000..a6baaed2 --- /dev/null +++ b/Samples~/OpenID Connect/GitHub/GitHubOIDCBootstrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bcd49101686deb46985b2d4caf07398 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity b/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity new file mode 100644 index 00000000..b5653a1c --- /dev/null +++ b/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity @@ -0,0 +1,670 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &254714363 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 254714366} + - component: {fileID: 254714365} + - component: {fileID: 254714364} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &254714364 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_Enabled: 1 +--- !u!20 &254714365 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &254714366 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &709749288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 709749291} + - component: {fileID: 709749290} + - component: {fileID: 709749289} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &709749289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &709749290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &709749291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &929522737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 929522739} + - component: {fileID: 929522738} + m_Layer: 0 + m_Name: Scene Documentation + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &929522738 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 929522737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6ba2ac043a0776a4d846aaf6ba38a734, type: 3} + m_Name: + m_EditorClassIdentifier: + title: 'Documentation of the ' + description: 'This scene gives an example how OpenID Connect Login can be used with + the GitHub login. + + Press F5 to trigger the login procedure.' + type: 0 + url: +--- !u!4 &929522739 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 929522737} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.58, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1037205111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1037205113} + - component: {fileID: 1037205112} + m_Layer: 0 + m_Name: Important Notice + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1037205112 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1037205111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6ba2ac043a0776a4d846aaf6ba38a734, type: 3} + m_Name: + m_EditorClassIdentifier: + title: Important Note - Register Client First + description: 'Important: To use this scene, you will first need to register your + own client on the GitHub administration site (see the following url) - there are + no client credentials shipped with this example. + + If you want to test both deep linking and the in-editor server, you need to create + two separate clients with the callback URIs set to i5:// and 127.0.0.1, respectively.' + type: 1 + url: https://github.com/settings/applications/new +--- !u!4 &1037205113 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1037205111} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.24, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1115967326 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1115967327} + - component: {fileID: 1115967328} + m_Layer: 0 + m_Name: Tester + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1115967327 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1115967326} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.23018031, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1115967328 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1115967326} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97e93daa98e42f046be85897f6196fdd, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1328610290 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 5962829298817573850, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299931686350, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299931686350, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Pivot.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247583, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Name + value: Fullscreen Console + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e6f9d8ad5c93e564c9c70b96f675d36b, type: 3} +--- !u!1 &1758836339 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1758836341} + - component: {fileID: 1758836340} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1758836340 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1758836339} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1758836341 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1758836339} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1780600240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1780600243} + - component: {fileID: 1780600241} + m_Layer: 0 + m_Name: Service Bootstrapper + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1780600241 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1780600240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2bcd49101686deb46985b2d4caf07398, type: 3} + m_Name: + m_EditorClassIdentifier: + deepLinkClient: {fileID: 11400000, guid: 8c071ab4ddaa3dc48bba3f9f4a947800, type: 2} + serverClient: {fileID: 11400000, guid: f165a3fb78409a7469f4d0ffe7ffb340, type: 2} +--- !u!4 &1780600243 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1780600240} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.23018031, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity.meta b/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity.meta new file mode 100644 index 00000000..6399d13f --- /dev/null +++ b/Samples~/OpenID Connect/GitHub/OpenID Connect GitHub.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 080cb9cd1e5d59f449ac423771b07d8d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Learning Layers.meta b/Samples~/OpenID Connect/Learning Layers.meta new file mode 100644 index 00000000..24d24c5b --- /dev/null +++ b/Samples~/OpenID Connect/Learning Layers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08cf567dfe74d824998c41e05b92da04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/LearningLayersBootstrapper.cs b/Samples~/OpenID Connect/Learning Layers/LearningLayersBootstrapper.cs similarity index 76% rename from Samples~/OpenID Connect/LearningLayersBootstrapper.cs rename to Samples~/OpenID Connect/Learning Layers/LearningLayersBootstrapper.cs index 76780809..9acfcebb 100644 --- a/Samples~/OpenID Connect/LearningLayersBootstrapper.cs +++ b/Samples~/OpenID Connect/Learning Layers/LearningLayersBootstrapper.cs @@ -1,5 +1,6 @@ using i5.Toolkit.Core.OpenIDConnectClient; using i5.Toolkit.Core.ServiceCore; +using UnityEngine; namespace i5.Toolkit.Core.Examples.OpenIDConnectClient { @@ -8,15 +9,19 @@ namespace i5.Toolkit.Core.Examples.OpenIDConnectClient /// public class LearningLayersBootstrapper : BaseServiceBootstrapper { + [SerializeField] + private ClientDataObject learningLayersClientData; + protected override void RegisterServices() { OpenIDConnectService oidc = new OpenIDConnectService(); oidc.OidcProvider = new LearningLayersOidcProvider(); + oidc.OidcProvider.ClientData = learningLayersClientData.clientData; // this example shows how the service can be used on an app for multiple platforms #if !UNITY_EDITOR oidc.RedirectURI = "i5:/"; #else - oidc.RedirectURI = "https://www.google.com"; + oidc.RedirectURI = "https://www.google.com"; #endif ServiceManager.RegisterService(oidc); } diff --git a/Samples~/OpenID Connect/LearningLayersBootstrapper.cs.meta b/Samples~/OpenID Connect/Learning Layers/LearningLayersBootstrapper.cs.meta similarity index 100% rename from Samples~/OpenID Connect/LearningLayersBootstrapper.cs.meta rename to Samples~/OpenID Connect/Learning Layers/LearningLayersBootstrapper.cs.meta diff --git a/Samples~/OpenID Connect/OpenID Connect Learning Layers.unity b/Samples~/OpenID Connect/Learning Layers/OpenID Connect Learning Layers.unity similarity index 89% rename from Samples~/OpenID Connect/OpenID Connect Learning Layers.unity rename to Samples~/OpenID Connect/Learning Layers/OpenID Connect Learning Layers.unity index fa0ba894..4cc46bf0 100644 --- a/Samples~/OpenID Connect/OpenID Connect Learning Layers.unity +++ b/Samples~/OpenID Connect/Learning Layers/OpenID Connect Learning Layers.unity @@ -194,6 +194,72 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &709749288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 709749291} + - component: {fileID: 709749290} + - component: {fileID: 709749289} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &709749289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &709749290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &709749291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &929522737 GameObject: m_ObjectHideFlags: 0 @@ -338,11 +404,9 @@ MonoBehaviour: m_GameObject: {fileID: 1115967326} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a32f588f565d88b4ebe635530dd60900, type: 3} + m_Script: {fileID: 11500000, guid: 97e93daa98e42f046be85897f6196fdd, type: 3} m_Name: m_EditorClassIdentifier: - learningLayersClientData: {fileID: 11400000, guid: 3325119f0762270419e0d0940be7dc20, - type: 2} --- !u!1001 &1328610290 PrefabInstance: m_ObjectHideFlags: 0 @@ -590,6 +654,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 001453952e2d99a479e690ee2df2117d, type: 3} m_Name: m_EditorClassIdentifier: + learningLayersClientData: {fileID: 11400000, guid: a35bc5145a3d8594ca05fffd8ad733ec, + type: 2} --- !u!4 &1780600243 Transform: m_ObjectHideFlags: 0 diff --git a/Samples~/OpenID Connect/OpenID Connect Learning Layers.unity.meta b/Samples~/OpenID Connect/Learning Layers/OpenID Connect Learning Layers.unity.meta similarity index 100% rename from Samples~/OpenID Connect/OpenID Connect Learning Layers.unity.meta rename to Samples~/OpenID Connect/Learning Layers/OpenID Connect Learning Layers.unity.meta diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel.meta new file mode 100644 index 00000000..314b3634 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc6674b2660cfc340ad4fbd554bb174b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs b/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs new file mode 100644 index 00000000..e82f449e --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs @@ -0,0 +1,8 @@ +using i5.Toolkit.Core.OpenIDConnectClient; + +namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +{ + public class GitHubOidcService : OpenIDConnectService + { + } +} \ No newline at end of file diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs.meta new file mode 100644 index 00000000..7fee80cd --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/GitHubOIDCService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 366e2fdfbe05049438f4fd2e542e8d55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs b/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs new file mode 100644 index 00000000..be71e3c0 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs @@ -0,0 +1,8 @@ +using i5.Toolkit.Core.OpenIDConnectClient; + +namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +{ + public class LearningLayersOidcService : OpenIDConnectService + { + } +} \ No newline at end of file diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs.meta new file mode 100644 index 00000000..ff5e9cbc --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/LearningLayersOIDCService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 866a4178658395c478d1f464a1e56953 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs new file mode 100644 index 00000000..c28afe2b --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs @@ -0,0 +1,59 @@ +using i5.Toolkit.Core.Examples; +using i5.Toolkit.Core.Examples.OpenIDConnectClient; +using i5.Toolkit.Core.OpenIDConnectClient; +using i5.Toolkit.Core.ServiceCore; +using UnityEngine; + +namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +{ + public class MultiProviderBootstrapper : BaseServiceBootstrapper + { + [SerializeField] private ClientDataObject learningLayersData; + [SerializeField] private ClientDataObject gitHubDeepLinkData; + [SerializeField] private ClientDataObject gitHubServerData; + + protected override void RegisterServices() + { + // Step 1: set up the provider like normal + // however: use a separate class that inherits from OpenIDConnectService + // for each provider that you want to register + + // first provider: Learning Layers + LearningLayersOidcProvider learningLayersProvider = new LearningLayersOidcProvider(); + learningLayersProvider.ClientData = learningLayersData.clientData; + LearningLayersOidcService learningLayersService = new LearningLayersOidcService(); + learningLayersService.OidcProvider = learningLayersProvider; + + // second provider: GitHub + GitHubOidcProvider githubProvider = new GitHubOidcProvider(); + GitHubOidcService githubService = new GitHubOidcService(); + githubService.OidcProvider = githubProvider; + // GitHub only allows one redirect URI per client in its client registration + // therefore, you need to create multiple ones if you need deep linking and the server redirect + // this example also shows how to already set up the client data +#if !UNITY_EDITOR + githubProvider.ClientData = gitHubDeepLinkData.clientData; +#else + githubProvider.ClientData = gitHubServerData.clientData; +#endif + + + // Step 2: set up the redirect URIs of both services +#if !UNITY_EDITOR + learningLayersService.RedirectURI = "i5:/"; + githubService.RedirectURI = "i5:/"; +#else + learningLayersService.RedirectURI = "https://google.com"; + githubService.RedirectURI = "https://www.google.com"; +#endif + + // Step 3: register both services at the service manager + ServiceManager.RegisterService(learningLayersService); + ServiceManager.RegisterService(githubService); + } + + protected override void UnRegisterServices() + { + } + } +} \ No newline at end of file diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs.meta new file mode 100644 index 00000000..40a0bf39 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderBootstrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2624727619478d419e941e44be2e316 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs new file mode 100644 index 00000000..c7f661db --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs @@ -0,0 +1,91 @@ +using i5.Toolkit.Core.OpenIDConnectClient; +using i5.Toolkit.Core.ServiceCore; +using i5.Toolkit.Core.Utilities; +using System; +using System.Threading.Tasks; +using UnityEngine; + +namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +{ + public class MultiProviderTester : MonoBehaviour + { + private bool isSubscribedToLearningLayers; + private bool isSubscribedToGitHub; + + private async Task Update() + { + if (Input.GetKeyDown(KeyCode.F1)) + { + // learning layers login + // only subscribe to the event if it was not yet done before, e.g. in a failed login attempt + if (!isSubscribedToLearningLayers) + { + ServiceManager.GetService().LoginCompleted += MultiProviderTester_LearningLayersLoginCompleted; + isSubscribedToLearningLayers = true; + } + ServiceManager.GetService().OpenLoginPage(); + } + else if (Input.GetKeyDown(KeyCode.F2)) + { + if (ServiceManager.GetService().IsLoggedIn) + { + IUserInfo info = await ServiceManager.GetService().GetUserDataAsync(); + i5Debug.Log("Logged in user at Learning Layers: " + info.Username, this); + } + else + { + i5Debug.Log("Cannot get user info because you are not logged in. Press F1 to log in at Learning Layers.", this); + } + } + else if (Input.GetKeyDown(KeyCode.F3)) + { + // github login + // only subscribe to the event if it was not yet done before, e.g. in a failed login attempt + if (!isSubscribedToGitHub) + { + ServiceManager.GetService().LoginCompleted += MultiProviderTester_GitHubLoginCompleted; + isSubscribedToGitHub = true; + } + ServiceManager.GetService().OpenLoginPage(); + } + else if (Input.GetKeyDown(KeyCode.F4)) + { + if (ServiceManager.GetService().IsLoggedIn) + { + IUserInfo info = await ServiceManager.GetService().GetUserDataAsync(); + i5Debug.Log("Logged in user at GitHub: " + info.Username, this); + } + else + { + i5Debug.Log("Cannot get user info because you are not logged in. Press F3 to log in at GitHub.", this); + } + } + } + + private async void MultiProviderTester_LearningLayersLoginCompleted(object sender, EventArgs e) + { + i5Debug.Log("Login completed", this); + LearningLayersOidcService lloidcService = ServiceManager.GetService(); + i5Debug.Log(lloidcService.AccessToken, this); + lloidcService.LoginCompleted -= MultiProviderTester_LearningLayersLoginCompleted; + isSubscribedToLearningLayers = false; + + IUserInfo userInfo = await lloidcService.GetUserDataAsync(); + i5Debug.Log("Currently logged in user: " + userInfo.FullName + + " (username: " + userInfo.Username + ") with the mail address " + userInfo.Email, this); + } + + private async void MultiProviderTester_GitHubLoginCompleted(object sender, EventArgs e) + { + i5Debug.Log("Login completed", this); + GitHubOidcService ghoidcService = ServiceManager.GetService(); + i5Debug.Log(ghoidcService.AccessToken, this); + ghoidcService.LoginCompleted -= MultiProviderTester_GitHubLoginCompleted; + isSubscribedToGitHub = false; + + IUserInfo userInfo = await ghoidcService.GetUserDataAsync(); + i5Debug.Log("Currently logged in user: " + userInfo.FullName + + " (username: " + userInfo.Username + ") with the mail address " + userInfo.Email, this); + } + } +} \ No newline at end of file diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs.meta new file mode 100644 index 00000000..78067cc7 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/MultiProviderTester.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6fbc8f57e1653ea488c7099302c96678 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity b/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity new file mode 100644 index 00000000..f252b301 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity @@ -0,0 +1,676 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &254714363 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 254714366} + - component: {fileID: 254714365} + - component: {fileID: 254714364} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &254714364 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_Enabled: 1 +--- !u!20 &254714365 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &254714366 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 254714363} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &709749288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 709749291} + - component: {fileID: 709749290} + - component: {fileID: 709749289} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &709749289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &709749290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &709749291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709749288} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &929522737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 929522739} + - component: {fileID: 929522738} + m_Layer: 0 + m_Name: Scene Documentation + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &929522738 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 929522737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6ba2ac043a0776a4d846aaf6ba38a734, type: 3} + m_Name: + m_EditorClassIdentifier: + title: 'Documentation of the ' + description: 'This scene gives an example how OpenID Connect Login can be used with + multiple login providers in parallel. + + Press F1 to trigger the login procedure for Learning Layers. + + Press F2 to verify your login status at Learning Layers by logging your username. + + Press F3 to trigger the login procedure for GitHub. + + Press F4 to verify your login status at GitHub by logging your username.' + type: 0 + url: +--- !u!4 &929522739 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 929522737} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.58, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1037205111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1037205113} + - component: {fileID: 1037205112} + m_Layer: 0 + m_Name: Important Notice + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1037205112 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1037205111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6ba2ac043a0776a4d846aaf6ba38a734, type: 3} + m_Name: + m_EditorClassIdentifier: + title: Important Note - Register Client First + description: 'Important: To use this scene, you will first need to register your + own client data for each provider separately - there are no client credentials + shipped with this example. + + To do this, follow the TODO instructions in one of the single provider examples.' + type: 1 + url: +--- !u!4 &1037205113 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1037205111} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.24, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1115967326 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1115967327} + - component: {fileID: 1115967328} + m_Layer: 0 + m_Name: Tester + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1115967327 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1115967326} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.23018031, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1115967328 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1115967326} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6fbc8f57e1653ea488c7099302c96678, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1328610290 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 5962829298817573850, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299778845467, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299931686350, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829299931686350, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247579, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Pivot.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5962829300182247583, guid: e6f9d8ad5c93e564c9c70b96f675d36b, + type: 3} + propertyPath: m_Name + value: Fullscreen Console + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e6f9d8ad5c93e564c9c70b96f675d36b, type: 3} +--- !u!1 &1758836339 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1758836341} + - component: {fileID: 1758836340} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1758836340 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1758836339} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1758836341 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1758836339} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1780600240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1780600243} + - component: {fileID: 1780600241} + m_Layer: 0 + m_Name: Service Bootstrapper + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1780600241 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1780600240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2624727619478d419e941e44be2e316, type: 3} + m_Name: + m_EditorClassIdentifier: + learningLayersData: {fileID: 11400000, guid: a35bc5145a3d8594ca05fffd8ad733ec, type: 2} + gitHubDeepLinkData: {fileID: 11400000, guid: 8c071ab4ddaa3dc48bba3f9f4a947800, type: 2} + gitHubServerData: {fileID: 11400000, guid: f165a3fb78409a7469f4d0ffe7ffb340, type: 2} +--- !u!4 &1780600243 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1780600240} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.23018031, y: -0.029292732, z: -0.5443495} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity.meta b/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity.meta new file mode 100644 index 00000000..693496a8 --- /dev/null +++ b/Samples~/OpenID Connect/Multiple Providers in Parallel/OpenID Connect Multiple Providers Parallel.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 736b35deefceb26469b3664d509f9011 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/OpenID Connect/OpenIDConnectTester.cs b/Samples~/OpenID Connect/OpenIDConnectTester.cs index 6fcfca5a..50381378 100644 --- a/Samples~/OpenID Connect/OpenIDConnectTester.cs +++ b/Samples~/OpenID Connect/OpenIDConnectTester.cs @@ -1,15 +1,11 @@ -using i5.Toolkit.Core.OpenIDConnectClient; -using i5.Toolkit.Core.ServiceCore; +using i5.Toolkit.Core.ServiceCore; using i5.Toolkit.Core.Utilities; using UnityEngine; -namespace i5.Toolkit.Core.Examples.OpenIDConnectClient +namespace i5.Toolkit.Core.OpenIDConnectClient { public class OpenIDConnectTester : MonoBehaviour { - [SerializeField] - private ClientDataObject learningLayersClientData; - private bool isSubscribedToOidc = false; // Update is called once per frame @@ -17,10 +13,6 @@ private void Update() { if (Input.GetKeyDown(KeyCode.F5)) { - LearningLayersOidcProvider provider = new LearningLayersOidcProvider(); - provider.ClientData = learningLayersClientData.clientData; - ServiceManager.GetService().OidcProvider = provider; - // only subscribe to the event if it was not yet done before, e.g. in a failed login attempt if (!isSubscribedToOidc) { diff --git a/Samples~/OpenID Connect/OpenIDConnectTester.cs.meta b/Samples~/OpenID Connect/OpenIDConnectTester.cs.meta index e65e2cd6..63d8c600 100644 --- a/Samples~/OpenID Connect/OpenIDConnectTester.cs.meta +++ b/Samples~/OpenID Connect/OpenIDConnectTester.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a32f588f565d88b4ebe635530dd60900 +guid: 97e93daa98e42f046be85897f6196fdd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs b/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs new file mode 100644 index 00000000..289273f6 --- /dev/null +++ b/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs @@ -0,0 +1,321 @@ +using FakeItEasy; +using i5.Toolkit.Core.OpenIDConnectClient; +using i5.Toolkit.Core.TestHelpers; +using i5.Toolkit.Core.Utilities; +using NUnit.Framework; +using System.Collections; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.TestTools; + +namespace i5.Toolkit.Core.Tests.OpenIDConnectClient +{ + public class GithubOIDCProviderTests + { + [Test] + public void Constructor_Initialized_ContentLoaderNotNull() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + + Assert.IsNotNull(ghoidc.RestConnector); + } + + [Test] + public void Constructor_Initialized_JsonWrapperNotNull() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + + Assert.IsNotNull(ghoidc.JsonSerializer); + } + + [UnityTest] + public IEnumerator GetAccessCodeFromTokenAsync_NoClientData_ReturnsEmptyString() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + ghoidc.RestConnector = A.Fake(); + + LogAssert.Expect(LogType.Error, + new Regex(@"\w*No client data supplied for the OpenID Connect Client\w*")); + + Task task = ghoidc.GetAccessTokenFromCodeAsync("", ""); + + yield return AsyncTest.WaitForTask(task); + + string res = task.Result; + + Assert.IsEmpty(res); + } + + [UnityTest] + public IEnumerator GetAccessCodeFromTokenAsync_WebResponseSuccess_ReturnsToken() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored, A>.Ignored)) + .Returns(Task.FromResult(new WebResponse("json string", null, 200))); + ghoidc.RestConnector = restConnector; + ghoidc.ClientData = A.Fake(); + GitHubAuthorizationFlowAnswer answer = new GitHubAuthorizationFlowAnswer(); + answer.access_token = "myAccessToken"; + IJsonSerializer serializer = A.Fake(); + A.CallTo(() => serializer.FromJson(A.Ignored)) + .Returns(answer); + ghoidc.JsonSerializer = serializer; + + Task task = ghoidc.GetAccessTokenFromCodeAsync("", ""); + + yield return AsyncTest.WaitForTask(task); + + string res = task.Result; + + Assert.AreEqual(answer.access_token, res); + } + + [UnityTest] + public IEnumerator GetAccessCodeFromTokenAsync_WebResponseFailed_ReturnsEmptyToken() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored, A>.Ignored)) + .Returns(Task.FromResult(new WebResponse("my error", 400))); + ghoidc.RestConnector = restConnector; + ghoidc.ClientData = A.Fake(); + ghoidc.JsonSerializer = A.Fake(); + + LogAssert.Expect(LogType.Error, + new Regex(@"\w*my error\w*")); + + Task task = ghoidc.GetAccessTokenFromCodeAsync("", ""); + + yield return AsyncTest.WaitForTask(task); + + string res = task.Result; + + Assert.IsEmpty(res); + } + + [Test] + public void GetAccessToken_TokenProvided_ExtractsToken() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + redirectParameters.Add("token", "myAccessToken"); + + string res = ghoidc.GetAccessToken(redirectParameters); + + Assert.AreEqual("myAccessToken", res); + } + + [Test] + public void GetAccessToken_TokenNotProvided_ReturnsEmptyToken() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + + LogAssert.Expect(LogType.Error, new Regex(@"\w*Redirect parameters did not contain access token\w*")); + + string res = ghoidc.GetAccessToken(redirectParameters); + + Assert.IsEmpty(res); + } + + [UnityTest] + public IEnumerator GetUserInfoAsync_WebResponseSuccessful_ReturnsUserInfo() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) + .Returns(new WebResponse("answer", null, 200)); + ghoidc.RestConnector = restConnector; + GitHubUserInfo userInfo = new GitHubUserInfo("tester", "tester@test.com"); + IJsonSerializer serializer = A.Fake(); + A.CallTo(() => serializer.FromJson(A.Ignored)) + .Returns(userInfo); + ghoidc.JsonSerializer = serializer; + + Task task = ghoidc.GetUserInfoAsync(""); + + yield return AsyncTest.WaitForTask(task); + + IUserInfo res = task.Result; + + Assert.AreEqual(userInfo.Email, res.Email); + } + + [UnityTest] + public IEnumerator GetUserInfoAsync_WebResponseFailed_ReturnsNull() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) + .Returns(new WebResponse("This is a simulated error", 400)); + ghoidc.RestConnector = restConnector; + + LogAssert.Expect(LogType.Error, new Regex(@"\w*This is a simulated error\w*")); + + Task task = ghoidc.GetUserInfoAsync(""); + + yield return AsyncTest.WaitForTask(task); + + IUserInfo res = task.Result; + + Assert.IsNull(res); + } + + [UnityTest] + public IEnumerator GetUserInfoAsync_JsonParseFailed_ReturnsNull() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) + .Returns(new WebResponse("answer", null, 200)); + ghoidc.RestConnector = restConnector; + GitHubUserInfo userInfo = new GitHubUserInfo("tester", "tester@test.com"); + IJsonSerializer serializer = A.Fake(); + A.CallTo(() => serializer.FromJson(A.Ignored)) + .Returns(null); + ghoidc.JsonSerializer = serializer; + + LogAssert.Expect(LogType.Error, new Regex(@"\w*Could not parse user info\w*")); + + Task task = ghoidc.GetUserInfoAsync(""); + + yield return AsyncTest.WaitForTask(task); + + IUserInfo res = task.Result; + + Assert.IsNull(res); + } + + [UnityTest] + public IEnumerator CheckAccessTokenAsync_WebResponseSuccessful_ReturnsTrue() + { + GitHubOidcProvider lloidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) + .Returns(new WebResponse("answer", null, 200)); + lloidc.RestConnector = restConnector; + GitHubUserInfo userInfo = new GitHubUserInfo("tester", "tester@test.com"); + IJsonSerializer serializer = A.Fake(); + A.CallTo(() => serializer.FromJson(A.Ignored)) + .Returns(userInfo); + lloidc.JsonSerializer = serializer; + + Task task = lloidc.CheckAccessTokenAsync(""); + + yield return AsyncTest.WaitForTask(task); + + bool res = task.Result; + + Assert.IsTrue(res); + } + + [UnityTest] + public IEnumerator CheckAccessTokenAsync_WebResponseFailed_ReturnsFalse() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IRestConnector restConnector = A.Fake(); + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) + .Returns(new WebResponse("This is a simulated error", 400)); + ghoidc.RestConnector = restConnector; + + LogAssert.Expect(LogType.Error, new Regex(@"\w*This is a simulated error\w*")); + + Task task = ghoidc.CheckAccessTokenAsync(""); + + yield return AsyncTest.WaitForTask(task); + + bool res = task.Result; + + Assert.IsFalse(res); + } + + [Test] + public void OpenLoginPage_UriGiven_BrowserOpened() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + IBrowser browser = A.Fake(); + ghoidc.Browser = browser; + ghoidc.ClientData = A.Fake(); + string[] testScopes = new string[] { "testScope" }; + + ghoidc.OpenLoginPage(testScopes, "http://www.test.com"); + + A.CallTo(() => browser.OpenURL(A.That.Contains("http://www.test.com"))).MustHaveHappenedOnceExactly(); + A.CallTo(() => browser.OpenURL(A.That.Contains("testScope"))).MustHaveHappenedOnceExactly(); + } + + [Test] + public void GetAuthorizationCode_CodeProvided_ExtractsCode() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + redirectParameters.Add("code", "myCode"); + string res = ghoidc.GetAuthorizationCode(redirectParameters); + + Assert.AreEqual("myCode", res); + } + + [Test] + public void GetAuthorizationCode_CodeNotProvided_ReturnsEmptyString() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + + LogAssert.Expect(LogType.Error, new Regex(@"\w*Redirect parameters did not contain authorization code\w*")); + + string res = ghoidc.GetAuthorizationCode(redirectParameters); + + Assert.IsEmpty(res); + } + + [Test] + public void ParametersContainError_NoError_ReturnsFalse() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + + bool res = ghoidc.ParametersContainError(redirectParameters, out string message); + + Assert.IsFalse(res); + } + + [Test] + public void ParametersContainError_NoError_ErrorMessageEmpty() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + + bool res = ghoidc.ParametersContainError(redirectParameters, out string message); + + Assert.IsEmpty(message); + } + + [Test] + public void ParametersContainError_ErrorGiven_ReturnsTrue() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + redirectParameters.Add("error", "This is a simulated error"); + + bool res = ghoidc.ParametersContainError(redirectParameters, out string message); + + Assert.IsTrue(res); + } + + [Test] + public void ParametersContainError_ErrorGiven_ErrorMessageSet() + { + GitHubOidcProvider ghoidc = new GitHubOidcProvider(); + Dictionary redirectParameters = new Dictionary(); + string errorMsg = "This is a simulated error"; + redirectParameters.Add("error", errorMsg); + + bool res = ghoidc.ParametersContainError(redirectParameters, out string message); + + Assert.AreEqual(errorMsg, message); + } + } +} diff --git a/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs.meta b/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs.meta new file mode 100644 index 00000000..13aac086 --- /dev/null +++ b/Tests/Editor/OpenID Connect/GithubOidcProviderTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c37f6ad824f507442a696121d3fdb68e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Editor/OpenID Connect/LearningLayersOIDCProviderTests.cs b/Tests/Editor/OpenID Connect/LearningLayersOIDCProviderTests.cs index 9aa4d0fb..2b4ff632 100644 --- a/Tests/Editor/OpenID Connect/LearningLayersOIDCProviderTests.cs +++ b/Tests/Editor/OpenID Connect/LearningLayersOIDCProviderTests.cs @@ -53,7 +53,7 @@ public IEnumerator GetAccessCodeFromTokenAsync_WebResponseSuccess_ReturnsToken() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored)) + A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored, A>.Ignored)) .Returns(Task.FromResult(new WebResponse("json string", null, 200))); lloidc.RestConnector = restConnector; lloidc.ClientData = A.Fake(); @@ -78,7 +78,7 @@ public IEnumerator GetAccessCodeFromTokenAsync_WebResponseFailed_ReturnsEmptyTok { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored)) + A.CallTo(() => restConnector.PostAsync(A.Ignored, A.Ignored, A>.Ignored)) .Returns(Task.FromResult(new WebResponse("my error", 400))); lloidc.RestConnector = restConnector; lloidc.ClientData = A.Fake(); @@ -126,7 +126,7 @@ public IEnumerator GetUserInfoAsync_WebResponseSuccessful_ReturnsUserInfo() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.GetAsync(A.Ignored)) + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) .Returns(new WebResponse("answer", null, 200)); lloidc.RestConnector = restConnector; LearningLayersUserInfo userInfo = new LearningLayersUserInfo("tester", "tester@test.com", "Tester"); @@ -149,7 +149,7 @@ public IEnumerator GetUserInfoAsync_WebResponseFailed_ReturnsNull() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.GetAsync(A.Ignored)) + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) .Returns(new WebResponse("This is a simulated error", 400)); lloidc.RestConnector = restConnector; @@ -169,7 +169,7 @@ public IEnumerator GetUserInfoAsync_JsonParseFailed_ReturnsNull() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.GetAsync(A.Ignored)) + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) .Returns(new WebResponse("answer", null, 200)); lloidc.RestConnector = restConnector; LearningLayersUserInfo userInfo = new LearningLayersUserInfo("tester", "tester@test.com", "Tester"); @@ -194,7 +194,7 @@ public IEnumerator CheckAccessTokenAsync_WebResponseSuccessful_ReturnsTrue() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.GetAsync(A.Ignored)) + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) .Returns(new WebResponse("answer", null, 200)); lloidc.RestConnector = restConnector; LearningLayersUserInfo userInfo = new LearningLayersUserInfo("tester", "tester@test.com", "Tester"); @@ -217,7 +217,7 @@ public IEnumerator CheckAccessTokenAsync_WebResponseFailed_ReturnsFalse() { LearningLayersOidcProvider lloidc = new LearningLayersOidcProvider(); IRestConnector restConnector = A.Fake(); - A.CallTo(() => restConnector.GetAsync(A.Ignored)) + A.CallTo(() => restConnector.GetAsync(A.Ignored, A>.Ignored)) .Returns(new WebResponse("This is a simulated error", 400)); lloidc.RestConnector = restConnector; diff --git a/package.json b/package.json index 58f75f9c..117e7226 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.i5.toolkit.core", - "version": "1.3.4", + "version": "1.4.0", "displayName": "i5 Toolkit for Unity", "description": "This package contains a collection of tools, features and assets for the development of Unity projects", "unity": "2018.4", @@ -37,7 +37,7 @@ }, { "displayName": "OpenID Connect", - "description": "Example how to implement an OpenID Connect client in Unity; note: you need to add client credentials to use the example", + "description": "Examples showing how to implement an OpenID Connect client in Unity; note: you need to add client credentials to use the examples", "path": "Samples~/OpenID Connect" }, {