public static TokenHandleResult HandleIdpIdToken(Session session, idP idP, JWT JWT) { SqlCommand cmd = session.db.NewConnection.CreateCommand(); try { cmd.Parameters.AddWithValue("@IDPID@", idP.IdpID); cmd.Parameters.AddWithValue("@SUBJECT@", JWT.Payload["sub"].ToString()); cmd.CommandText = "SELECT UserID FROM [Security.Users] WHERE [OpenID.IdpID] = @IDPID@ AND [OpenID.Subject] = @SUBJECT@"; SqlDataReader rdr = cmd.ExecuteReader(); try { if (rdr.HasRows) { if (session.UserID == Guid.Empty) { rdr.Read(); Guid UserID = rdr.GetGuid(0); rdr.Close(); UserTools.Logon(session, UserID); HandleJwtClaims(session, idP, JWT); return(TokenHandleResult.Success); } else { return(TokenHandleResult.SubjectAlreadyBoundToAnotherAccount); } } } finally { rdr.Close(); } if (session.UserID == Guid.Empty) { Guid newUserID = UserTools.CreateUser(session.db); UserTools.Logon(session, newUserID); } cmd.Parameters.AddWithValue("@USERID@", session.UserID); cmd.CommandText = "UPDATE [Security.Users] SET [OpenID.IdpID] = @IDPID@, [OpenID.Subject] = @SUBJECT@ WHERE UserID = @USERID@"; int affected = cmd.ExecuteNonQuery(); if (affected != 1) { return(TokenHandleResult.FailedToBindToCurrentUserAccount); } HandleJwtClaims(session, idP, JWT); return(TokenHandleResult.Success); } finally { cmd.Connection.Close(); } }
private static bool HandleJwtClaims(Session Session, idP idP, JWT JWT) { if ( idP.ClaimsEmail != null && idP.ClaimsEmail != "" && JWT.Payload.TryGetValue(idP.ClaimsEmail, out object oClaimEmail) && MailAddress.TryCreate(oClaimEmail.ToString(), out MailAddress mailAddress) ) { UserTools.SetUserEmail(Session.db, Session.UserID, mailAddress); } return(true); }
public static async Task Login(HttpContext con) { Session session = con.InitializeSession(); idP idP = OpenID.GetIDP(session.db, Guid.Parse(con.Request.RouteValues["IdpID"].ToString())); if (idP == null) { con.Response.Redirect("/_Error/OpenID/idp-does-not-exist"); return; } if (!con.Request.Query.ContainsKey("code") || con.Request.Query["code"] == "") { con.Response.Redirect("/_Error/OpenID/code-missing"); return; } string code = con.Request.Query["code"]; HttpClient hc = new(); HttpRequestMessage msg = new(); msg.RequestUri = new(idP.EndpointToken); msg.Method = HttpMethod.Post; if (idP.ClientSecret != null) { byte[] secret = Encoding.Default.GetBytes(HttpUtility.UrlEncode(idP.ClientID) + ":" + idP.ClientSecret); msg.Headers.Authorization = new("Basic", Convert.ToBase64String(secret)); } FormUrlEncodedContent form = new(new Dictionary <string, string>() { { "grant_type", "authorization_code" }, { "code", code }, { "redirect_uri", idP.GetRedirectURI(session) }, { "client_id", idP.ClientID } }); msg.Content = new StreamContent(await form.ReadAsStreamAsync()); msg.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); HttpResponseMessage hResponse = await hc.SendAsync(msg); try { hResponse.EnsureSuccessStatusCode(); } catch (Exception e) { con.Response.Redirect("/_Error/OpenID/token-endpoint-bad-status-response?msg=" + e.Message); return; } Stream sResponse = await hResponse.Content.ReadAsStreamAsync(); Dictionary <string, object> jResposne; try { jResposne = await JsonSerializer.DeserializeAsync <Dictionary <string, object> >(sResponse); } catch { con.Response.Redirect("/_Error/OpenID/jwt-deserialize-error"); return; } if (!jResposne.TryGetValue("id_token", out object idToken)) { sResponse.Position = 0; con.Response.Redirect("/_Error/OpenID/jwt-missing?idp_response=" + HttpUtility.UrlEncode(await new StreamReader(sResponse).ReadToEndAsync())); return; } JWT JWT; try { JWT = new(idToken.ToString()); } catch { con.Response.Redirect("/_Error/OpenID/jwt-invalid"); return; } OpenID.TokenHandleResult result = OpenID.HandleIdpIdToken(session, idP, JWT); if (result != OpenID.TokenHandleResult.Success) { con.Response.Redirect("/_Error/OpenID/" + result.ToString()); return; } con.Response.Redirect("/"); await Task.CompletedTask; }