diff --git a/GoogleLogin.sln b/GoogleLogin.sln new file mode 100644 index 0000000..733c898 --- /dev/null +++ b/GoogleLogin.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Web +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleLogin", "GoogleLogin\GoogleLogin.csproj", "{5F0B1F6D-BAE4-4C26-B704-34CF840A387A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5F0B1F6D-BAE4-4C26-B704-34CF840A387A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F0B1F6D-BAE4-4C26-B704-34CF840A387A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F0B1F6D-BAE4-4C26-B704-34CF840A387A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F0B1F6D-BAE4-4C26-B704-34CF840A387A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GoogleLogin/GoogleLogin.csproj b/GoogleLogin/GoogleLogin.csproj new file mode 100644 index 0000000..7320fbe --- /dev/null +++ b/GoogleLogin/GoogleLogin.csproj @@ -0,0 +1,131 @@ + + + + + Debug + AnyCPU + + + 2.0 + {5F0B1F6D-BAE4-4C26-B704-34CF840A387A} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + GoogleLogin + GoogleLogin + v4.5 + true + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + header.aspx + ASPXCodeBehind + + + header.aspx + + + login.aspx + ASPXCodeBehind + + + login.aspx + + + + footer.aspx + ASPXCodeBehind + + + footer.aspx + + + + + Web.config + + + Web.config + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 0 + / + http://localhost:50002/ + False + False + + + False + + + + + + \ No newline at end of file diff --git a/GoogleLogin/GoogleLogin.csproj.user b/GoogleLogin/GoogleLogin.csproj.user new file mode 100644 index 0000000..3f8536e --- /dev/null +++ b/GoogleLogin/GoogleLogin.csproj.user @@ -0,0 +1,31 @@ + + + + Debug|Any CPU + + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + True + + + + + \ No newline at end of file diff --git a/GoogleLogin/Properties/AssemblyInfo.cs b/GoogleLogin/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c6d12c3 --- /dev/null +++ b/GoogleLogin/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GoogleLogin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GoogleLogin")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c912d57c-9055-4ff4-a6d7-917cf96ef38a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GoogleLogin/Web.Debug.config b/GoogleLogin/Web.Debug.config new file mode 100644 index 0000000..2e302f9 --- /dev/null +++ b/GoogleLogin/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/GoogleLogin/Web.Release.config b/GoogleLogin/Web.Release.config new file mode 100644 index 0000000..c358444 --- /dev/null +++ b/GoogleLogin/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/GoogleLogin/Web.config b/GoogleLogin/Web.config new file mode 100644 index 0000000..6da78ec --- /dev/null +++ b/GoogleLogin/Web.config @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/GoogleLogin/bin/GoogleLogin.dll b/GoogleLogin/bin/GoogleLogin.dll new file mode 100644 index 0000000..c5e45d8 Binary files /dev/null and b/GoogleLogin/bin/GoogleLogin.dll differ diff --git a/GoogleLogin/bin/GoogleLogin.pdb b/GoogleLogin/bin/GoogleLogin.pdb new file mode 100644 index 0000000..3da1260 Binary files /dev/null and b/GoogleLogin/bin/GoogleLogin.pdb differ diff --git a/GoogleLogin/footer.aspx b/GoogleLogin/footer.aspx new file mode 100644 index 0000000..3aae533 --- /dev/null +++ b/GoogleLogin/footer.aspx @@ -0,0 +1,27 @@ +
+ +
+ + <% } %> + +
+ + <% + string path = @"C:\certs\"; + + if (hasWriteAccessToFolder(path)) + { + Response.Write("
Access to " + path + " appears to be okay, but " + + "check permissions if certificate caching doesn't work.
"); + } + else + { + Response.Write("
Access to " + path + " is not verified. Check permissions on that folder!
"); + } + %> +
+ \ No newline at end of file diff --git a/GoogleLogin/footer.aspx.cs b/GoogleLogin/footer.aspx.cs new file mode 100644 index 0000000..6a6d2cd --- /dev/null +++ b/GoogleLogin/footer.aspx.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace GoogleLogin +{ + public partial class WebForm1 : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/GoogleLogin/footer.aspx.designer.cs b/GoogleLogin/footer.aspx.designer.cs new file mode 100644 index 0000000..0ab8836 --- /dev/null +++ b/GoogleLogin/footer.aspx.designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GoogleLogin +{ + + + public partial class WebForm1 + { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/GoogleLogin/header.aspx b/GoogleLogin/header.aspx new file mode 100644 index 0000000..05a31df --- /dev/null +++ b/GoogleLogin/header.aspx @@ -0,0 +1,94 @@ +

Google OAuth2 Demonstration v1.0

+

+ This is an example application implementing Google OAuth2 authentication for a C# web application. + This software is provided AS IS by A Better Geek and is solely for testing purposes. Please remember + to test all code thoroughly in your own application before moving to production. +

+

+ Some notes: +

+ +
+ <% if (Request.Cookies["client_id"] == null && Request.Form["client_id"] == null && Session["loggedin"] != "yes") { %> +

+ You are seeing this message because you have not configured the application yet. Setting the below + parameters will create local browser cookies storing each parameter. In order to protect your application's + client secret, please remember to clear the cookies for this page when you are done testing! +

+

+ If you haven't already done so, you need to first go to Google's API Console + and create your application. Note down your client id and client secret for use in the below form. + You also need to use the URL of this page, including the port number for localhost, as the redirect URI for + your application. +

+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ + <% } else if (Request.Cookies["client_id"] == null && Request.Form["client_id"] != null) { %> + + <% + //write POSTDATA to cookies + Response.Cookies["client_id"].Value = Request.Form["client_id"]; + Response.Cookies["client_secret"].Value = Request.Form["client_secret"]; + Response.Cookies["redirect_uri"].Value = Request.Form["redirect_uri"]; + + Response.Redirect(Request.Form["redirect_uri"]); + %> + + <% } else { %> \ No newline at end of file diff --git a/GoogleLogin/header.aspx.cs b/GoogleLogin/header.aspx.cs new file mode 100644 index 0000000..a0d6e25 --- /dev/null +++ b/GoogleLogin/header.aspx.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace GoogleLogin +{ + public partial class header : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/GoogleLogin/header.aspx.designer.cs b/GoogleLogin/header.aspx.designer.cs new file mode 100644 index 0000000..63c20b9 --- /dev/null +++ b/GoogleLogin/header.aspx.designer.cs @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GoogleLogin { + + + public partial class header { + } +} diff --git a/GoogleLogin/login.aspx b/GoogleLogin/login.aspx new file mode 100644 index 0000000..0357993 --- /dev/null +++ b/GoogleLogin/login.aspx @@ -0,0 +1,67 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="login.aspx.cs" Inherits="GoogleLogin.login" %> +<% + //if the user logs out, this clears the session and reloads the page. + if (Request.QueryString["logout"] == "yes") + { + Session.Clear(); + Response.Redirect("/login.aspx"); + } +%> + + + Google OAuth2 Authentication Demo, by A Better Geek + + + + + + + + <% + string code = Request.QueryString["code"]; + + if (code != null && Session["loggedin"] != "yes") + { + //if there is a "code" value in the querystring and no login session present + //then log in using Google + string client_id = Request.Cookies["client_id"].Value; + string client_secret = Request.Cookies["client_secret"].Value; + string redirect_uri = Request.Cookies["redirect_uri"].Value; + string grant_type = "authorization_code"; + + //the state token in the return URL needs to be verified first. + string gState = Request["state"]; + + if (gState == Convert.ToString(Session["state"])) + { + string gurl = "code=" + code + "&client_id=" + client_id + + "&client_secret=" + client_secret + "&redirect_uri=" + redirect_uri + "&grant_type=" + grant_type; + Response.Write(GoogleLogin(gurl)); + + } + else + { + Response.Write("
Please start over. If you're seeing this message, the session ID verification failed.
"); + } + } + else if (Session["loggedin"] == "yes") + { + Response.Write("
Already logged in. You can logout if you'd like.
"); + } + else + { + %> +

+ & + response_type=code&scope=openid%20email&state=<%=Session["state"]%>& + redirect_uri=<%=Request.Cookies["redirect_uri"].Value%>">Login With Google +

+ <% + Response.Write("
Not logged in.
"); + } + %> + + + + + \ No newline at end of file diff --git a/GoogleLogin/login.aspx.cs b/GoogleLogin/login.aspx.cs new file mode 100644 index 0000000..360cb43 --- /dev/null +++ b/GoogleLogin/login.aspx.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +//these are additional libraries needed beyond the default ones +//Reference: http://blog.abettergeek.com/?p=472#part2 +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Web.Script.Serialization; + +namespace GoogleLogin +{ + public partial class login : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + //when the page loads, a random session token needs to be created + //this will be sent to Google to verify that the data hasn't been tampered with + + //create a random GUID as a token for preventing CSS attacks + //this only happens if a session doesn't already exist + if (Session["state"] == null) + { + Session["state"] = Guid.NewGuid(); + } + } + + public string GoogleLogin(string e) + { + string responseData = ""; + + try + { + // variables to store parameter values + string url = "https://accounts.google.com/o/oauth2/token"; + + // creates the post data for the POST request + string postData = (e); + + // create the POST request + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); + webRequest.Method = "POST"; + webRequest.ContentType = "application/x-www-form-urlencoded"; + webRequest.ContentLength = postData.Length; + + // POST the data + using (StreamWriter requestWriter2 = new StreamWriter(webRequest.GetRequestStream())) + { + requestWriter2.Write(postData); + } + + //This actually does the request and gets the response back + HttpWebResponse resp = (HttpWebResponse)webRequest.GetResponse(); + + string googleAuth; + + using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream())) + { + //dumps the HTML from the response into a string variable + googleAuth = responseReader.ReadToEnd(); + } + + //now that we have the responseData (which is a JSON array), we can do stuff with it. + + //process JSON array + JavaScriptSerializer js = new JavaScriptSerializer(); + gLoginInfo gli = js.Deserialize(googleAuth); + + //the id_token is what needs to be decoded to (a) verify it and (b) get some basic details about the user + //gli.id_token is in three parts. the first two are Base64 encoded plaintext. + string[] tokenArray = gli.id_token.Split(new Char[] { '.' }); + + //tokenArray[0] is the JSON header + //tokenArray[1] is the JSON payload + //tokenArray[2] is an encrypted digital signature + + //process header + JavaScriptSerializer js1 = new JavaScriptSerializer(); + gLoginHeader glh = js1.Deserialize(base64Decode(tokenArray[0])); + + //verify signature based on header data - the signature is tokenArray[2] + //we need the keyID, which is glh.kid + + + //use header data to validate signature + //if the signature is valid, we can process the payload + //once the payload is processed, we can either add a new user or log in an existing user + + if (verifySignature(glh.kid, tokenArray)) + { + //process payload + JavaScriptSerializer js2 = new JavaScriptSerializer(); + gLoginClaims glc = js2.Deserialize(base64Decode(tokenArray[1])); + + + //we can tell the session that we're logged in + Session["loggedin"] = "yes"; + responseData = "
You have successfully logged in using " + glc.email + + ". You can logout if you'd like.
"; + } + + } + catch (Exception ex) + { + //this shouldn't ever happen. + responseData = "
ERROR" + ex.StackTrace + "
"; + } + + return responseData; + } + + public class gLoginInfo + { + public string access_token, token_type, id_token; + public int expires_in; + } + + public class gTokenInfo + { + public string issuer, issued_to, audience, user_id, email, email_verified; + public int expires_in, issued_at; + } + + public class gLoginHeader + { + public string alg, kid; + } + + public class gLoginClaims + { + public string aud, iss, email_verified, at_hash, azp, email, sub; + public int exp, iat; + } + + public string base64Decode(string data) + { + //add padding with '=' to string to accommodate C# Base64 requirements + int strlen = data.Length + (4 - (data.Length % 4)); + char pad = '='; + string datapad; + + if (strlen == (data.Length + 4)) + { + datapad = data; + } + else + { + datapad = data.PadRight(strlen, pad); + } + + try + { + System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding(); + System.Text.Decoder utf8Decode = encoder.GetDecoder(); + + // create byte array to store Base64 string + byte[] todecode_byte = Convert.FromBase64String(datapad); + int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); + char[] decoded_char = new char[charCount]; + utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); + string result = new String(decoded_char); + return result; + } + catch (Exception e) + { + throw new Exception("Error in base64Decode: " + e.Message); + } + } + + public byte[] base64urldecode(string arg) + { + //this swaps out the characters in Base64Url encoding for valid Base64 syntax + //C# can't decode Base64 without doing this first + arg = arg.Replace('-', '+'); + arg = arg.Replace('_', '/'); + + int strlen = arg.Length + (4 - (arg.Length % 4)); + char pad = '='; + + if (strlen != (arg.Length + 4)) + { + arg = arg.PadRight(strlen, pad); + } + + //return the Base64 decoded data as a byte array, since that's what we need for RSA + byte[] arg2 = Convert.FromBase64String(arg); + + return arg2; + } + + public bool verifySignature(string kid, string[] jwt) + { + //this will return TRUE if the signature is valid or FALSE if it is invalid + //if the signature is invalid, we must not accept the user's login information! + + //by default, the signature isn't valid, just as a precaution + bool verified = false; + + //pull out the different elements from the original JWT provided by Google + string toVerify = jwt[0] + "." + jwt[1]; + string signature = jwt[2]; + + //the JWS is encoded in Base64 that C# doesn't like + //we need to replace some special characters and then Base64Decode this into a byte array + byte[] sig = base64urldecode(signature); + + //the header and payload need to be converted to a byte array + byte[] data = Encoding.UTF8.GetBytes(toVerify); + + //before we do anything else, we need to locally cache Google's public certificate, if it isn't already + cacheCertificate(kid); + + //now we can validate the signature against our locally-cached certificate + //create an X509 cert from the google certificate in local cache + X509Certificate gcert = X509Certificate.CreateFromCertFile(@"C:\certs\" + kid + ".cer"); + + //we need to use the new X509Certificate2 subclass in order to pull the public key from the certificate + X509Certificate2 gcert2 = new X509Certificate2(gcert); + + //this lets us use the public key from the cached Google certificate + using (var rsa = (RSACryptoServiceProvider)gcert2.PublicKey.Key) + { + //create a new byte array that contains a SHA256 hash of the JSON header and payload + byte[] hash; + using (SHA256 sha256 = SHA256.Create()) + { + hash = sha256.ComputeHash(data); + } + + //Create an RSAPKCS1SignatureDeformatter object and pass it the + //RSACryptoServiceProvider to transfer the key information. + RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa); + RSADeformatter.SetHashAlgorithm("SHA256"); + + //Verify the hash and return the appropriate bool value + if (RSADeformatter.VerifySignature(hash, sig)) + { + verified = true; + } + else + { + verified = false; + } + } + + return verified; + } + + public void cacheCertificate(string kid) + { + //if the certificate ID doesn't already exist as a local certificate file, download it from Google + if (!File.Exists(@"C:\certs\" + kid + ".cer")) + { + //pull JSON certificate data from Google + string url = "https://www.googleapis.com/oauth2/v1/certs"; + WebRequest request = WebRequest.Create(url); + WebResponse response = request.GetResponse(); + Stream certdata = response.GetResponseStream(); + + string certs; + + using (StreamReader sr = new StreamReader(certdata)) + { + certs = sr.ReadToEnd(); + } + + //certs are returned as a JSON object + JavaScriptSerializer js = new JavaScriptSerializer(); + + //convert the JSON object into a dictionary + //pick the certificate that matches the returned key ID from Google + Dictionary cts = js.Deserialize>(certs); + string b64 = cts[kid]; + + //write the certificate to a file with the .cer extension, which identifies it as a digital certificate + //these are stored outside the web server filespace + //at some point the server needs to have a daily script running that deletes certificates that are more than 48 hours old + System.IO.File.WriteAllText(@"C:\certs\" + kid + ".cer", b64); + } + } + + //This is just for testing that your configuration allows write access to the folder where cached certificates are stored. + //You don't need this in your own project. + public bool hasWriteAccessToFolder(string folderPath) + { + try + { + // Attempt to get a list of security permissions from the folder. + // This will raise an exception if the path is read only or do not have access to view the permissions. + System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath); + return true; + } + catch (UnauthorizedAccessException) + { + return false; + } + } + } +} \ No newline at end of file diff --git a/GoogleLogin/login.aspx.designer.cs b/GoogleLogin/login.aspx.designer.cs new file mode 100644 index 0000000..fd69899 --- /dev/null +++ b/GoogleLogin/login.aspx.designer.cs @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GoogleLogin { + + + public partial class login { + } +} diff --git a/GoogleLogin/obj/Debug/.NETFramework,Version=v4.5.AssemblyAttributes.cs b/GoogleLogin/obj/Debug/.NETFramework,Version=v4.5.AssemblyAttributes.cs new file mode 100644 index 0000000..e5dc9b8 --- /dev/null +++ b/GoogleLogin/obj/Debug/.NETFramework,Version=v4.5.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] diff --git a/GoogleLogin/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/GoogleLogin/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..f4b7691 Binary files /dev/null and b/GoogleLogin/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/GoogleLogin/obj/Debug/GoogleLogin.csproj.FileListAbsolute.txt b/GoogleLogin/obj/Debug/GoogleLogin.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..a99593d --- /dev/null +++ b/GoogleLogin/obj/Debug/GoogleLogin.csproj.FileListAbsolute.txt @@ -0,0 +1,5 @@ +K:\Development\bitfork\project\GoogleLogin\GoogleLogin\bin\GoogleLogin.dll +K:\Development\bitfork\project\GoogleLogin\GoogleLogin\bin\GoogleLogin.pdb +K:\Development\bitfork\project\GoogleLogin\GoogleLogin\obj\Debug\GoogleLogin.csprojResolveAssemblyReference.cache +K:\Development\bitfork\project\GoogleLogin\GoogleLogin\obj\Debug\GoogleLogin.dll +K:\Development\bitfork\project\GoogleLogin\GoogleLogin\obj\Debug\GoogleLogin.pdb diff --git a/GoogleLogin/obj/Debug/GoogleLogin.csprojAssemblyReference.cache b/GoogleLogin/obj/Debug/GoogleLogin.csprojAssemblyReference.cache new file mode 100644 index 0000000..bc7d262 Binary files /dev/null and b/GoogleLogin/obj/Debug/GoogleLogin.csprojAssemblyReference.cache differ diff --git a/GoogleLogin/obj/Debug/GoogleLogin.csprojResolveAssemblyReference.cache b/GoogleLogin/obj/Debug/GoogleLogin.csprojResolveAssemblyReference.cache new file mode 100644 index 0000000..2f654d1 Binary files /dev/null and b/GoogleLogin/obj/Debug/GoogleLogin.csprojResolveAssemblyReference.cache differ diff --git a/GoogleLogin/obj/Debug/GoogleLogin.dll b/GoogleLogin/obj/Debug/GoogleLogin.dll new file mode 100644 index 0000000..c5e45d8 Binary files /dev/null and b/GoogleLogin/obj/Debug/GoogleLogin.dll differ diff --git a/GoogleLogin/obj/Debug/GoogleLogin.pdb b/GoogleLogin/obj/Debug/GoogleLogin.pdb new file mode 100644 index 0000000..3da1260 Binary files /dev/null and b/GoogleLogin/obj/Debug/GoogleLogin.pdb differ diff --git a/GoogleLogin/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/GoogleLogin/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs new file mode 100644 index 0000000..e69de29 diff --git a/GoogleLogin/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/GoogleLogin/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs new file mode 100644 index 0000000..e69de29 diff --git a/GoogleLogin/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/GoogleLogin/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs new file mode 100644 index 0000000..e69de29 diff --git a/GoogleLogin/scripts.js b/GoogleLogin/scripts.js new file mode 100644 index 0000000..343fabf --- /dev/null +++ b/GoogleLogin/scripts.js @@ -0,0 +1,28 @@ +function validateForm() { + var inputs = document.getElementsByTagName("input"); + var list = ""; + + for (i = 0; i < inputs.length; i++) { + if (inputs[i].value == "") { + list = list + inputs[i].id + " must be completed.\n"; + } + } + + if (list != "") { + alert(list); + return false; + } + + return true; +} + +function deleteAllCookies() { + var cookies = document.cookie.split(";"); + + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i]; + var eqPos = cookie.indexOf("="); + var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; + } +} \ No newline at end of file diff --git a/GoogleLogin/style.css b/GoogleLogin/style.css new file mode 100644 index 0000000..a3bd07a --- /dev/null +++ b/GoogleLogin/style.css @@ -0,0 +1,74 @@ +BODY { + margin-left: 25%; + width: 50%; + font-family: Calibri, sans-serif; +} +UL { + margin-top: -.75em; + font-size: .8em; +} +UL LI { + padding: .25em 0; +} +UL UL { + margin-top: 0em; + font-size: 1em; +} +FORM#setCookies { + overflow: hidden; + width: 400px; + margin: auto; +} +.row { + clear: both; +} +.label, .input, .submit { + height: 25px; + float: left; +} +.label { + width: 100px; + padding-right: 5px; + line-height: 25px; + text-align: right; + font-size: .8em; +} +.input, .submit { + width: 250px; +} +.input INPUT { + width: 100%; + font-family: Calibri, sans-serif; +} +.submit { + text-align: center; +} +.alert, .good, .bad { + clear: both; + margin: 1em 0.5em; + padding: 5px; + background: #ff9; + border: 1px dotted #f90; + font-size: .8em; + font-style: italic; + color: #c60; +} +.good, .bad { + font-style: normal +} +.good { + background: #cfc; + border-color: #0c3; + color: #060; +} +.bad { + background: #fcc; + border-color: #f00; + color: #900; +} +.footer { + text-align: center; + font-size: .8em; + font-style: italic; + color: #666; +} \ No newline at end of file diff --git a/README.md b/README.md index 121af94..e01fd9c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ -# DotNetOAuth2 +# .NET OAuth2 -A secure implementation of OAuth2 using vanilla ASP.NET C#. Requires no third-party libraries or assemblies. \ No newline at end of file +A secure implementation of OAuth2 using vanilla ASP.NET C#. Requires no third-party libraries or assemblies. + +**This is proof-of-concept and was developed in September 2013. I do not recommend implementing this code in a production environment without careful evaluation of the security implications.** + +This project implements [OAuth2](https://oauth.net/2/), which is a standardized means of implementing third-party authentication for web applications. Securing user accounts is a serious endeavor that requires an adequate understanding of the complex security concerns around protecting users' authentication and identification information. OAuth2 (and its predecessor, OpenID) attempts to address this scenario, by making it easy for web developers to support authentication from a variety of popular online services, such as Google, Microsoft, Twitter, and Facebook. This project uses Google authentication. + +My implementation relies exclusively on vanilla .NET Framework 4.5 assemblies. Although this project implements Google authentication, it should be trivial to modify the code to use other OAuth2 providers. + +For a detailed breakdown of the code, check out the [wiki](/ABG/DotNetOAuth2/wiki). \ No newline at end of file