I've built a DocuSign integration that works fine with a sandbox account, but I'm having trouble with a live account. I'm using the C# SDK. I'm using an authorization code grant with impersonation. Debugging shows that a LoginInformation object is created, but it's LoginAccounts property is null, which, of course, breaks the code attempting to get the appropriate base URL for subsequent API calls. Any suggestions?
public static ApiClient GetDocuSignClient()
{
string accountType = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignAccountType");
string integratorKey = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignIntegratorKey");
string userID = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignUserID");
string rsaPrivate = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignRSAKey");
string basePath = accountType == "sandbox" ? "account-d.docusign.com" : "account.docusign.com";
// this gets replaced when we communicate with the api
string clientBasePath = accountType == "sandbox" ? "https://demo.docusign.net/restapi" : "https://www.docusign.net/restapi";
int expirationHours = 1;
if (accountType == "" || integratorKey == "" || userID == "" || rsaPrivate == "")
throw new System.Configuration.ConfigurationErrorsException("All DocuSign settings must be set in Settings->Integration->DocuSign");
ApiClient dsClient = new ApiClient(clientBasePath);
dsClient.ConfigureJwtAuthorizationFlow(integratorKey, userID, basePath, HttpContext.Current.Server.MapPath(rsaPrivate), expirationHours);
AuthenticationApi authClient = new AuthenticationApi(dsClient.Configuration);
LoginInformation loginInfo = authClient.Login();
// find the default account for this user
foreach (LoginAccount loginAcct in loginInfo.LoginAccounts)
{
...
Per our DS Docs also, With OAUTH (and JWT), you should not use Login_information API, instead you need to use User Info API Call to get the base URI. Once you get the Base URI then you all other non-authentication related APIs using this Base URI. Demo environment is only at one data center, so with your current code it is working fine in Sandbox, but PROD has multiple data centers like NA1, NA2, NA3, EU1, and your account can be in any one of them, so to know the exact URI to use to hit data center for creating envelopes, you need to use User Info API call to know the Base URI.
Currently in your code, you have hard coded the BaseUri (or client Base Path) clientBasePath = https://www.docusign.net/restapi, in this hard coding you are assuming that your PROD account is in NA1, but as I mentioned earlier it can be in any other datacenters also, so please change the code to call userinfo/ API call. Our SDK has this code (of incorrectly calling LoginInformation instead of userinfo/) incorrectly written and I have already reported it to DS Dev center team to fix this flow.
I've found what are either errors or very misleading statements in the DocuSign API documentation. It seems the oauth/userinfo call returns the base URL for an account in different formats for sandbox and live accounts. The following code is a bit messy, but it's working for both.
public static ApiClient GetDocuSignClient()
{
string accountType = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignAccountType");
string integratorKey = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignIntegratorKey");
string userID = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignUserID");
string rsaPrivate = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignRSAKey");
string basePath = accountType == "sandbox" ? "account-d.docusign.com" : "account.docusign.com";
// this gets replaced when we communicate with the api
string clientBasePath = accountType == "sandbox" ? "https://demo.docusign.net/restapi" : "https://www.docusign.net/restapi";
int expirationHours = 1;
if (accountType == "" || integratorKey == "" || userID == "" || rsaPrivate == "")
throw new System.Configuration.ConfigurationErrorsException("All DocuSign settings must be set in Settings->Integration->DocuSign");
ApiClient dsClient = new ApiClient(clientBasePath);
dsClient.ConfigureJwtAuthorizationFlow(integratorKey, userID, basePath, HttpContext.Current.Server.MapPath(rsaPrivate), expirationHours);
var rsUserClient = new RestSharp.RestClient("https://" + basePath); ;
RestSharp.RestRequest acctReq = new RestSharp.RestRequest();
acctReq.Method = RestSharp.Method.GET;
acctReq.RequestFormat = RestSharp.DataFormat.Json;
acctReq.Resource = "oauth/userinfo";
// even though we're not using the SDK to get accounts, we can use the token it generates
AuthenticationApi authClient = new AuthenticationApi(dsClient.Configuration);
acctReq.AddHeader("Authorization", authClient.Configuration.DefaultHeader["Authorization"]);
RestSharp.IRestResponse rsResponse = rsUserClient.Execute(acctReq);
if (rsResponse.ResponseStatus != RestSharp.ResponseStatus.Completed || rsResponse.StatusCode != HttpStatusCode.OK)
{
if (rsResponse.ErrorException != null)
throw new WebException("DocuSign login failed: " + rsResponse.ErrorException.Message, rsResponse.ErrorException);
else if (rsResponse.StatusCode == HttpStatusCode.BadRequest)
throw new WebException(String.Format("DocuSign login failed. StatusCode: {0} <br/>ErrorDescription: {1}", rsResponse.StatusCode, rsResponse.Content));
else
throw new WebException(String.Format("DocuSign login failed. StatusCode: {0} ResponseStatus: {1}", rsResponse.StatusCode, rsResponse.ResponseStatus));
}
DocuSignLoginInfo loginInfo = JsonConvert.DeserializeObject<DocuSignLoginInfo>(rsResponse.Content);
DocuSignLoginAccount toUse = null;
foreach (var loginAcct in loginInfo.Accounts)
{
if (toUse == null)
{
toUse = loginAcct; // use first account
}
else if (loginAcct.IsDefault &&
((accountType == "sandbox" && loginAcct.Base_Uri.Contains("demo.")) ||
(accountType != "sandbox" && !loginAcct.Base_Uri.Contains("demo."))))
{
toUse = loginAcct; // use default account if appropriate
}
}
if (toUse == null)
{
throw new WebException("DocuSign login failed: " + loginInfo.Email + " doesn't have a login account we can use.");
}
else
{
SettingsKeyInfoProvider.SetValue("DocuSignAccountID", SiteContext.CurrentSiteName, toUse.Account_Id);
string[] separatingStrings = { "/v2" };
string restUrl = toUse.Base_Uri.Split(separatingStrings, StringSplitOptions.RemoveEmptyEntries)[0];
if (!restUrl.Contains("/restapi"))
restUrl += "/restapi";
// Update ApiClient with the new base url from login call
dsClient = new ApiClient(restUrl);
}
return dsClient;
}
public class DocuSignLoginAccount
{
public string Account_Id;
public string Account_Name;
public bool IsDefault;
public string Base_Uri;
}
public class EnvelopeBrief
{
public string EnvID;
public Signer CurrentSigner;
public string ClientUserID;
}
Related
I am currently working on an dotnet maui app and I need to integrate Sign in With Apple. But when I click the sign in button, It shows "invalid_request invalid web redirect url"
Tried solutions
I tried the solutions available here, but it is not working.
Other than that I have also read the documentation, also got help from tutorials such as this, this and this
Code
Initializing request:
//Initiating apple sign in request
WebAuthenticatorResult result = null;
if (scheme.Equals(Constants.apple, StringComparison.Ordinal)
&& DeviceInfo.Platform == DevicePlatform.iOS
&& DeviceInfo.Version.Major >= 13)
{
// Make sure to enable Apple Sign In in both the
// entitlements and the provisioning profile.
var options = new AppleSignInAuthenticator.Options
{
IncludeEmailScope = true,
IncludeFullNameScope = true,
};
result = await AppleSignInAuthenticator.AuthenticateAsync(options);
}
else
{
var authUrl = new Uri(Constants.authenticationUrl + scheme);
var callbackUrl = new Uri(Constants.callbackUrl);
result = await WebAuthenticator.AuthenticateAsync(authUrl, callbackUrl);
}
AuthToken = string.Empty;
// Get Name and Email from callback url
//if (result.Properties.TryGetValue("name", out var name) && !string.IsNullOrEmpty(name))
// AuthToken += $"Name: {name}{Environment.NewLine}";
//if (result.Properties.TryGetValue("email", out var email) && !string.IsNullOrEmpty(email))
// AuthToken += $"Email: {email}{Environment.NewLine}";
AuthToken += result?.AccessToken ?? result?.IdToken;
AuthCredential credential = null;
Handling results:
// WebAuthenticator Endpoint - use for social login e.g. Google, Facebook, Apple etc.
const string callbackScheme = "socialloginauthenticator";
[HttpGet("{scheme}")]
public async Task Get([FromRoute] string scheme)
{
var auth = await Request.HttpContext.AuthenticateAsync(scheme);
if (!auth.Succeeded
|| auth?.Principal == null
|| !auth.Principal.Identities.Any(id => id.IsAuthenticated)
|| string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token")))
{
// Not authenticated, challenge
await Request.HttpContext.ChallengeAsync(scheme);
}
else
{
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
var email = string.Empty;
email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value;
// Get parameters to send back to the callback
var qs = new Dictionary<string, string>
{
{ "access_token", auth.Properties.GetTokenValue("access_token") },
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
{ "expires_in", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() },
{ "email", email }
};
// Build the result url
var url = callbackScheme + "://#" + string.Join(
"&",
qs.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
// Redirect to final url
Request.HttpContext.Response.Redirect(url);
}
}
I have resolved the issue. The issue was with redirect uri in apple service I made.
The required uri was of format "www.example.com/signin-apple" while I was following "www.example.com/path/to/endpoints"
Hi I've looked through a lot of S.O. pages on this subject but mine is a little different. This has nothing to do with an anti-forgery protected login page or users hitting the back button. At our university we use University of Michigan's CoSign as a single-sign-on solution. Users are authenticated through cosign and on success the username is provided by the IIS server in Request.ServerVariables["REMOTE_USER"] and can then be used for authorization, etc.
Here's some code: in global.asax.cs:
Session["username"] = Request.ServerVariables["REMOTE_USER"];
On each page that might use Ajax (in a file Init.js; code from https://blog.alexmaccaw.com/jswebapps-csrf):
$(document).ready(function () {
SetCSRFHeader();
}
function SetCSRFHeader() {
var CSRF_HEADER = 'RequestVerificationToken';
var setCSRFToken = function (securityToken) {
jQuery.ajaxPrefilter(function (options, _, xhr) {
if (!xhr.crossDomain)
xhr.setRequestHeader(CSRF_HEADER, securityToken);
});
};
var theTokenVal = $('#__bothTokens').val();
setCSRFToken(theTokenVal);
}
In _Layout.cshtml:
#Html.AntiForgeryToken()
#{
string cookieToken, formToken, bothTokens;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
bothTokens = cookieToken + ":" + formToken;
}
<input type="hidden" id="__bothTokens" value="#(bothTokens)" />
I also wrote a class that implements IHttpModule to check all POST requests for the included header, parse it and validate it (code from https://security.stackexchange.com/questions/91164/how-to-check-the-origin-header-server-wide-in-iis-to-prevent-csrf):
public class HeaderCheck : IHttpModule
{
public HeaderCheck()
{
}
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
int errCode = 0;
int STATCODE = 403;
string cookieToken = "";
string formToken = "";
if (context.Request.HttpMethod == "POST") // only on POST requests
{
if (context.Request.Headers["Content-Type"] != null)
{
if (context.Request.Headers["Content-Type"] == "application/json;") // JSON check
{
if (context.Request.Headers["RequestVerificationToken"] != null)
{
string tokenHeaders = context.Request.Headers["RequestVerificationToken"];
string[] tokens = tokenHeaders.Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
else
{
errCode = 3;
}
}
else if (context.Request.Headers["Content-Type"].Length >= 19)
{
if (context.Request.Headers["Content-Type"].Substring(0, 19) == "multipart/form-data") // Form check
{
HttpCookie cookie = new HttpCookie("__RequestVerificationToken");
cookie = context.Request.Cookies["__RequestVerificationToken"];
formToken = context.Request.Form["__RequestVerificationToken"];
if (formToken == null) { tokenstr = "form null"; }
if (cookie != null)
{
cookieToken = cookie.Value;
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
else // cookie is null
{
errCode = 4;
}
}
}
else // neither acceptable content form
{
errCode = 5;
}
}
else // content type should not be null
{
errCode = 6;
}
if (errCode > 0)
{
try
{
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
catch (HttpAntiForgeryException e2)
{
string err = #"Antiforgery tokens not validated" +
"<br><b>Error in: </b>"
+ context.Request.Url.ToString()
+ "<br><b>Error Message: </b>"
+ e2.Message.ToString()
+ "<br><b>Stack Trace:</b><br>"
+ e2.StackTrace.ToString();
EmailContext.sendEmailOnError(err); // sends email to me for debugging
}
}
if (errCode > 0)
{
context.Response.StatusCode = STATCODE;
context.Response.Flush();
context.Response.End();
}
}
}
public void Dispose() { }
}
}
My questions: Why am I getting the error in the title of this question? How does AntiForgeryValidate know that the token was meant for me but somehow the token that's generated is for current user ""? Is there any way I can put the user into the token? I've even tried the advice at Reload AntiForgeryToken after a login to always regenerate the token the first time the user hits the home page (since they're already logged in at that point. Does this have anything to do with developing in visual studio in HTTP but the acceptance environment which is cosign-protected is https? Does it have anything to do with the fact that IIS is configured for Anonymous Authentication? (I think it needs to be to run under cosign).
Thanks for any advice.
EDIT: More and more I think this is due to IIS Anonymous Authentication being the only mode that's enabled. But any other mode requires some sort of second login, and since cosign is THE authentication provider, that doesn't help. So if anyone has any idea how to programmatically insert the user credentials received from cosign into IIS that might be the way forward.
i have an problem with C#, and if/else if string value.
It will return the right value, but it will be checked, and it will ever throw something else(If login is successfull)
Code:
public void UserLogin(string Username, string Password)
{
ConsoleLog Log = new ConsoleLog();
WebClient client = new WebClient();
ServerURL = "http://play.projectzeternity.tk/logonapi.php?login&user=" + Username + "&password=" + Password; // Logon API
byte[] html = client.DownloadData(ServerURL);
UTF8Encoding utf = new UTF8Encoding();
string response = utf.GetString(html); // Here is string - API Response
string check = Convert.ToString(response); // I tried converting to string, but it's not working.
Log.Log("Checking response...");
if (check == "UserNotExist") // User not exist = Successfull login
{
Log.Log("Response: UserNotExist");
ShowError("User doesn't exist!");
}
else if (check == "BadArguments") // == Successfull login
{
Log.Log("Response: BadArguments");
ShowError("Invalid arguments!");
}
else if (check == "PlayerIsBanned") // == Successfull login
{
Log.Log("Response: PlayerIsBanned");
ShowError("This account is banned for breaking rules!");
}
else if (check == "WrongPassword") // = Successfull login
{
Log.Log("Response: WrongPassword");
ShowError("Wrong password!");
}
else if (check == "UserAlreadyExist") // = Successfull login
{
Log.Log("Response: UserAlreadyExist");
ShowError("User already exists!");
}
else // Successfull login
{
Log.Log("Response: " + check);
IsLoggedIn = true;
LoginForm.SetActive(false);
RegisterForm.SetActive(false);
ConnectionStatus.SetActive(true);
ConnectionStatusText.text = "Connecting to master...";
PhotonNetwork.ConnectUsingSettings(GameOperations.PZVersion);
PhotonNetwork.playerName = Name;
PhotonNetwork.JoinLobby();
}
Log.Log("API response: " + response);
Log.Log("Converted response: " + check);
Name = Username;
}
It will join into API, and API returns the response, and i will give it into if/else, and value is null, why?
If i will print the response from API (Debug.Log), it will return the right response...
I asked on Unity Awsners, but nobody responsed. :(
Can you help me with that?
You can get a string directly from a WebClient request by using WebClient.DownloadString()—no need to handle raw byte data:
public void UserLogin(string Username, string Password)
{
ConsoleLog Log = new ConsoleLog();
WebClient client = new WebClient();
ServerURL = "http://play.projectzeternity.tk/logonapi.php?login&user=" + Username + "&password=" + Password; // Logon API
string check = client.DownloadString(ServerURL);
// validate the response here...
}
I have the following code(facebook C# SDK) to post to facebook wall :
public long? UploadPost(string intLinkTitle, string inMessage, string inLinkCaption, string inLinkUrl, string inLinkDescription, string inLinkUrlPicture)
{
object obj;
Facebook.JsonObject jsonObj;
FacebookClient client;
string access_token = ConfigurationManager.AppSettings["FacebookPageAccessToken"].ToString();
client = new FacebookClient(access_token);
var args = new Dictionary<string, object>();
args["message"] = inMessage;
args["caption"] = inLinkCaption;
args["description"] = inLinkDescription;
args["name"] = intLinkTitle;
args["picture"] = inLinkUrlPicture;
args["link"] = inLinkUrl;
if ((obj = client.Post("/" + ConfigurationManager.AppSettings["FacebookPageId"].ToString() + "/feed", args)) != null)
{
if ((jsonObj = obj as Facebook.JsonObject) != null)
{
if (jsonObj.Count > 0)
return long.Parse(jsonObj[0].ToString().Split('_').Last().ToString());
}
}
return null;
}
}
This works great as long as I post to my public facebook website page but when changing the FacebookPageId to a group id instead I get (FacebookApiException - #200) Permissions error.
My user are admin of both the group and the page.
I have tried to post the message from the Graph API Explorer with the following line : 294632750660619/feed/?message=test but there is a syntax problem here, have also tried 294632750660619/feed?message=test but with no success.
How do I post to the closed facebook group?
Okay, I found the correct way. This is what I hade to do :
Go to the https://developers.facebook.com/ and create a new application
Settings > Add platform(Website and set the site URL(for example localhost..)
Set the app to go live(status & review > Yes), to do this a email adress needs to be set under settings > Contact Email
Go to the Graph API Explorer
Choose the new app from the dropdown
Click Get Access Token
Choose correct permissions(user_groups, user_status, user_photos, manage_pages, publish_actions, read_insights and read_stream) and click Get Access Token. Now we bot a short lived tooken
Generate a extended user token (valid for 60 days) by using this URL(change parameters(3)) : https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=[app-id]&client_secret=[app-secret]&fb_exchange_token=[short-lived-token]
Use the generated none expiring access token in the application
Validate the Access token here : https://developers.facebook.com/tools/debug/access_token/
Use this code to upload post :
public long? UploadPost(string intLinkTitle, string inMessage, string inLinkCaption, string inLinkUrl, string inLinkDescription, string inLinkUrlPicture)
{
object obj;
Facebook.JsonObject jsonObj;
FacebookClient client;
string access_token = ConfigurationManager.AppSettings["FacebookPageAccessToken"].ToString();
client = new FacebookClient(access_token);
var args = new Dictionary<string, object>();
args["message"] = inMessage;
args["caption"] = inLinkCaption;
args["description"] = inLinkDescription;
args["name"] = intLinkTitle;
args["picture"] = inLinkUrlPicture;
args["link"] = inLinkUrl;
if ((obj = client.Post("/" + ConfigurationManager.AppSettings["FacebookPageId"].ToString() + "/feed", args)) != null)
{
if ((jsonObj = obj as Facebook.JsonObject) != null)
{
if (jsonObj.Count > 0)
return long.Parse(jsonObj[0].ToString().Split('_').Last().ToString());
}
}
return null;
}
And to get feed, use this :
private void GetFeed()
{
object obj;
Facebook.JsonObject jsonObj;
Facebook.JsonObject jsonPaging;
FacebookClient client;
int pageCount = 0;
string access_token;
string URL;
DateTime fetchFaceBookFeedFromDate;
DateTime? oldestPostFetched = null;
fetchFaceBookFeedFromDate = DateTime.Now.AddDays(-30);
access_token = ConfigurationManager.AppSettings["FacebookPageAccessToken"].ToString();
URL = "/" + ConfigurationManager.AppSettings["FacebookPageId"].ToString() + "/feed";
client = new FacebookClient(access_token);
while (URL.Length > 0 && pageCount < 1000)
{
if ((obj = client.Get(URL)) != null)
{
if ((jsonObj = obj as Facebook.JsonObject) != null && jsonObj.Count > 0)
{
if (jsonObj[0] is Facebook.JsonArray)
oldestPostFetched = SaveFacebookForumThread(jsonObj[0] as Facebook.JsonArray, fetchFaceBookFeedFromDate);
if (jsonObj.Keys.Contains("paging") && (jsonPaging = jsonObj["paging"] as Facebook.JsonObject) != null && jsonPaging.Keys.Contains("next"))
URL = jsonPaging["next"].ToString();
else
break;
}
}
pageCount++;
if (oldestPostFetched.HasValue && fetchFaceBookFeedFromDate > oldestPostFetched)
break;
}
}
I want to make a Cordova phone app and a web application. Both the application and the app share the same database.
On the mobile app, the user actions send requests to a web service ( over https ) that writes to the database. On the mobile app, I use https://oauth.io to let the user register and log in with multiple open auth providers. Trying to make it work for facebook, for now.
I just can't figure how to use the Identity user management in that context. Most of the examples I find are in the context of a web app where the user clicks and it calls the account controller. In my case, the oauth.io lib calls facebook, returns an access token, which I pass to my service.
The cordova app passes the accessToken to this method to my server side web service.
var client = new FacebookClient(accessToken);
if (client != null)
{
dynamic fbresult = client.Get("me");
if (fbresult["id"] != null)
{
var fbid = fbresult["id"].ToString();
and where do we go from now ?
how do I insert a new user
I tried this:
var user = new ApplicationUser() { UserName = fbresult["id"] };
Backend.Controllers.AccountController ac = new Controllers.AccountController();
ac.UserManager.CreateAsync(user);
Doesn't work because the usermanagement object inside the account controller is null.
There is an overload of the AccountController constructor but I have a feeling I'm doing this whole thing the wrong way.
Let's say the server side receives a facebook access token. How do use OWIN and Identity user management system from there?
Ok.
As suggested by a friend, I replaced the controllers etc from the original web api template for the ones in the Identity Sample Project
Here is the method called by the mobile app, with a angular jsonp
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string StartSession(string accessToken)
{
if (!HttpContext.Current.Request.IsAuthenticated)
{
var client = new FacebookClient(accessToken);
if (client != null)
{
dynamic fbresult = client.Get("me");
if (fbresult["id"] != null)
{
string fbid = fbresult["id"].ToString();
ApplicationUser user = null;
using (var context = new ApplicationDbContext())
{
user = context.Users.FirstOrDefault(u => u.UserName.ToString() == fbid);
}
if (user == null)
{
CreateUserAsync(fbid);
return "user created. ";
}
else
{
HttpContext.Current.Session["user"] = "holy fuck";
return "user logged in. ";
}
}
}
return "ok";
}
else
{
return "already auth !";
}
}
here is the CreateUserAsync I made
public async System.Threading.Tasks.Task<bool> CreateUserAsync(string fbid)
{
using (var context = new ApplicationDbContext())
{
var newUser = new ApplicationUser() { UserName = fbid, Email = "xxx#gmail.com" };
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
try
{
var result = await userManager.CreateAsync(newUser, "Admin#123456");
var test = await context.SaveChangesAsync();
return result.Succeeded;
}
catch (Exception ex)
{
throw ex;
}
}
}
And then, when the mobile app calls back my web service, I can check if the session exists like so:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public async Task<string> TestLogin(int id, string callback)
{
if (HttpContext.Current.Session["user"] != null)
{
return new JavaScriptSerializer().Serialize(new word() { Name = "woot" });
}
else
return new JavaScriptSerializer().Serialize(new word() { Name = "not logged" });
}
Yea, that's right. A if and a session. Just like I was doin' 13 years ago.
Also, while doing this abomination, I stumbled upon a hangin' problem in the IdentityConfig.cs file.
Apparantly, the problem is known by Microsoft and I guess it is probably fixed in the version 3 of Owin ? But I didn't know about that version 3 at that time, so I followed Program hangs during database initialization .
For some reason, some of the method posted in his solution didn't exist for me. I ended up fixing the code the best I could:
public static void InitializeIdentityForEF(ApplicationDbContext db)
{
//ApplicationUserManager userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(db));
const string name = "admin#example.com";
const string password = "Admin#123456";
const string roleName = "Admin";
IdentityRole adminRole = new IdentityRole(roleName);
//Create Role Admin if it does not exist
if (!roleManager.RoleExists(roleName))
{
roleManager.Create(adminRole);
PasswordHasher hasher = new PasswordHasher();
ApplicationUser adminUser = new ApplicationUser { UserName = name, Email = name, PasswordHash = hasher.HashPassword(password), LockoutEnabled = false };
db.Users.Add(adminUser);
IdentityUserRole userRole = new IdentityUserRole() { RoleId = adminRole.Id, UserId = adminUser.Id };
adminUser.Roles.Add(userRole);
var x = db.SaveChanges();
}
}
Also just in case someone is wondering how to call the svc service from the mobile, here is the code.
(it's a little bit messy, but the important parts are there.)
(keep in mind I am using https://oauth.io/ )
$scope.refresh = function () {
$http.jsonp("https://10.0.100.38:6443/Service1.svc/helloworld?id=1&callback=JSON_CALLBACK").success(function JSON_CALLBACK(result) {
OAuth.popup('facebook')
.done(function (oauthResult) {
oauthResult.me() // standardise lesfield firstname, first-name etc
.done(function (response) {
alert("3");
$http.jsonp("https://10.0.100.38:6443/Service1.svc/StartSession?accessToken=" +oauthResult.access_token + "&callback=JSON_CALLBACK").success(function JSON_CALLBACK(result) {
alert("done " +result); // StartSession serverside success ");
}).error(function (data, status, headers, config) {
alert("icierror2" +data + " " +status + " " +headers + " " + config);
$scope.status = status;
});
}).fail(function (error) {
alert("icierror3 " +error);
});
})
.fail(function (error) {
console.log(error);
});
alert(result.Name); // result de la svc request over https
}).error(function (data, status, headers, config) {
alert("icierror" +data + " " +status + " " + headers + " " +config);
$scope.status = status;
});
Problems
As of now, I am not creating a Login, only a user is created.
Also, the project's OWIN version is 2.0, and apparantly, a 3.0 exists.
To be honest, the more I read online the more I feel like everything I've done is a big hack around the right way to do it. I just couldn't figure it out. This is thing is incredibly huge, confusing, chaothic and broken. Yea, I've added an opinion to my answer.