As always: Im quite the noob, as you will prob see from the question.
I am playing around with Azure Wams in Xamarin.Android, and it seems to be a great tool. It logs in a user in Xamarin.Android greatly. My problem comes when i want the user to be able to log out and then log in with another account (im using Google for authentication). I used to be able to use it with a log out button, like this:
When logging in the AuthenticationToken is saved in a String for later use. So when the user confirms he wants to log out, i just UserAuth = String.Empty and then i call ConnectToMobileService() again:
public async Task ConnectToMobileService ()
{
try
{
CurrentPlatform.Init ();
client = new MobileServiceClient(
Constants.ApplicationURL,
Constants.ApplicationKey, progressHandler);
if (string.IsNullOrEmpty(UserAuth)) {
await Authenticate();
UserId = user.UserId;
await CreateTables();
await CheckUserId ();
}
else if (!string.IsNullOrEmpty(UserAuth)) {
client.CurrentUser = new MobileServiceUser(UserId);
client.CurrentUser.MobileServiceAuthenticationToken = (UserAuth);
await CreateTables();
}
}
catch (Exception e)
{
CreateAndShowDialog(e, "Error");
}
}
This used to re-launch the authentication-window for me, and the user logged in with hes new account - while the info is saved in preferences for use in other activities and so on. Well, after updating Xamarin and upgrading my license to Indie, this is no longer the case. Now it launces Authenticate for a short second, and then it goes straight back and acts as if the user logged in the exaxt way he did before.
I realize this i probably because there is some sharedpreference saved somewhere for the Wams. Ive studied the methods for clearing these i Java, but i have not been able to recreate them in C#.
client.Logout () does not seem to clear them alone. This is how i tried to recreatet the rest of it:
private void ClearPreferences(){
var prefs = this.GetSharedPreferences("UserDate", 0);
var editor = prefs.Edit ();
editor.Clear ();
editor.Commit ();
}
This does nothing. So, can anyone help me along? How do i reset it, so the users are able to log in with another account - or for example let a friend log in on their phone? Thanks in advance!
OK, so it turns out the info is stored as cookies by the auth provider. You have to both log out and clear the cookies. And it then works like a charm. This is how to clear cookies:
client.Logout ();
ClearCookies ();
await ConnectToMobileService ();
}
public static void ClearCookies () {
Android.Webkit.CookieSyncManager.CreateInstance (Android.App.Application.Context);
Android.Webkit.CookieManager.Instance.RemoveAllCookie ();
}
Related
I have a pretty standard ASP.NET Core 2.2 web app.
I'm running into an issue with downloading files that are stored on a Network Share. We are using a method of impersonation in code (client requirements) to access the file share. Uploading to the share with the provided credentials works fine, so we know that (a) the impersonation is working and (b) the files ARE at the destination. The issue I am having comes from Downloading the file. It's a pretty standard download link that points to an action in a controller that gets the file information from the database and uses two of the database values (PathToFile and Filename) to get the location of the file and pull it back to the controller, followed by returning a file:
var fileRecord = //Get the record from the database.
byte[] bytes = null;
if(fileRecord != null)
{
try
{
string fullPath = $"{fileRecord.PathToFile}\\{fileRecord.Filename}";
await ImpersonationHelper.Impersonate(async () => { bytes = await System.IO.File.ReadAllBytesAsync(fullPath); }, _settings);
}
catch (Exception e)
{
return NotFound();
}
}
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileRecord.Filename);
For reference:
public static async Task Impersonate(Action actionToExecute, ApplicationSettings settings)
{
IntPtr tokenHandle = new IntPtr(0);
SafeAccessTokenHandle safeAccessTokenHandle = null;
ImpersonateLogin login = new ImpersonateLogin(settings);
Task<bool> returnValue = Task.Run(() => LogonUser(login.username, login.domain, login.password, 2, 0, out safeAccessTokenHandle));
if (false == returnValue.Result)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
if(safeAccessTokenHandle != null)
await returnValue.ContinueWith(antecedent => WindowsIdentity.RunImpersonated(safeAccessTokenHandle, () =>
{
actionToExecute();
}));
}
}
Locally, it works fine (we skip the impersonation with an appsetting) and the file comes back and set up as a download in the browser.
On the server, however, it doesn't work, but it also does work. It's strange: Clicking on the link will lead to an error page:
but refreshing this error page (ie. re-requesting that file) over and over again will make it work (usually every 2-4 refreshes will return the file correctly).
Has anyone encountered this, or something like this that can offer some insight?
As it turns out, it (seemingly?) had something to do with the method(s) being async.
Once I removed the (forced) async call to the impersonation, and all async calls right to the "Download" action, it all lined up and works 100% of the time now. From what I could find online, it looks like it was a "timing" issue with async/sync calls. The impersonation would happen AFTER the download file, so the user wouldn't have permission to actually fetch the file to download, but in some cases, the impersonation would happen first, so the file would come back. Making everything "non-async" fixed the issues I was having.
I want to make a login system and automatic login after login:
login from Google then retrieve username.
guest mode but retrieve the username from the firebase database.
I have 2 scenes on Unity scene no.1 is about login system and no.2 The game main menu. What I want from the scene no.1 is after they log in there will be username at the scene no.2. and if I exit the game then I open the app again will be automated login.
I have tried to retrieve but the username not changed,here the script.
SignManager.cs
public class SignManager : MonoBehaviour
{
public InputField nameText;
public static string playerName;
public static SignManager signManager;
User user = new User();
private void Awake()
{
if (signManager != null)
{
Destroy(gameObject);
}
else
{
signManager = this;
DontDestroyOnLoad(gameObject);
}
}
public void onSubmit()
{
playerName = nameText.text;
posttodatabase();
}
public void posttodatabase()
{
User user = new User();
RestClient.Put("https://recruiter-wars.firebaseio.com/" + playerName + ".json", user);
SceneManager.LoadScene("Demo");
}
Retrieve.cs
User user = new User();
public Text namePlayer;
public static string playerName;
private void Start()
{
RetrieveFromDatabase();
}
public void getUser()
{
playerName = namePlayer.text;
}
public void RetrieveFromDatabase()
{
RestClient.Get<User>("https://recruiter-wars.firebaseio.com/" + namePlayer + ".json").Then(ResponseHelper =>
{
user = ResponseHelper;
getUser();
});
}
im using RestClient for this
You generally shouldn't do this. The path to your realtime database will be public knowledge to anyone who downloads your game. Although you can use rules to secure it, typically you use the user id from Firebase Authentication is used to do so as it will be securely passed around with any database operation from the standard SDK.
With that said, I can tell you how I would accomplish what you want with the official Firebase SDK then give you hints that might help you with a third party rest-based client (I haven't used FirebaseREST myself).
For the Firebase Unity SDK, I would use Firebase Authentication for this entire flow. I'm mostly following along with this.
Before you do anything, you will need to call FirebaseApp.CheckAndFixDependenciesAsync(). I would use a continuation to ensure this succeeds. You only have to do it once per run of your game, but calling it multiple times won't hurt you more than the brief performance spikes it may cause:
async InitFirebase() {
var result = await FirebaseApp.CheckAndFixDependenciesAsync();
if (result == DependencyStatus.Available) {
// do Firebase stuff here
}
}
Logging in is as simple as:
var auth = FirebaseAuth.DefaultInstance;
var credential = Firebase.Auth.GoogleAuthProvider.GetCredential(googleIdToken, googleAccessToken);
var user = await auth.SignInWithCredentialAsync(credential);
If you want the Firebase user in a new scene, or even a new launch of the game, you can call:
var user = FirebaseAuth.DefaultInstance.CurrentUser;
If this is null you have to sign in again.
What's happening under the hood is that you pass user credentials in to the Firebase Authentication SDK. You can create or log in a user in your Firebase project there, and you get back a Firebase id token and a Firebase refresh token (you can get a little insight into this process here and here).
The ID token is short lived (~1hr), but the refresh is valid until some event happens (ex: a user is deleted or disabled). You can choose to store this token in something like the Unity PlayerPrefs (although you might want to be careful with it) and try to refresh the token the next time you launch the game. This will be way more secure than just reading a value from a database before authenticating a user.
If you want to persist the ID token between scenes, you can also try storing this in the PlayerPrefs. I would prefer a ScriptableObject with a public property you can cache it in for the current run of your game, but that's up to your own preferences around persisting data between scenes (a MonoBehaviour singleton marked DontDestoryOnLoad will work just as well for example).
I would recommend using the official Unity Auth SDK if you can. This is one of the Firebase products that works on desktop and mobile.
I have done a class which already works with the Dropbox API uploading files, downloading, deleting and so on. It has been working quite well since I was just using my own access token, but I need to register other users and a single but "big" problem appeared: retrieving the access token.
1.- Redirect URI? I'm starting to doubt why do I need this. I finally used this URI (https://www.dropbox.com/1/oauth2/redirect_receiver) because "The redirect URI you use doesn't really matter" Of course I included this one on my app config on Dropbox.
2.- I reach the user's account (I can see the user's count increased and I see the app has access to the user's account.
3.- I have a breakpoint on my code to inspect the variables in order to apply the DropboxOAuth2Helper.ParseTokenFragment but I have no success on there.
This is my code, but on the if before the try catch is where it gets stuck:
string AccessToken;
const string AppKey = "theOneAtmyAppConfigOnDropbox";
const string redirectUrl = "https://www.dropbox.com/1/oauth2/redirect_receiver";
string oauthUrl =
$#"https://www.dropbox.com/1/oauth2/authorize?response_type=token&redirect_uri={redirectUrl}&client_id={AppKey}";
private string oauth2State;
private bool Result;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Start(AppKey, webBrowser1);
webBrowser1.Navigating += Browser_Navigating;
}
private void Start(string appKey, WebBrowser w)
{
this.oauth2State = Guid.NewGuid().ToString("N");
Uri authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OauthResponseType.Token, appKey, redirectUrl, state: oauth2State);
w.Navigate(authorizeUri);
}
private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (!e.Url.ToString().StartsWith(redirectUrl, StringComparison.InvariantCultureIgnoreCase))
{
// we need to ignore all navigation that isn't to the redirect uri.
return;
}
try
{
OAuth2Response result = DropboxOAuth2Helper.ParseTokenFragment(e.Url);
if (result.State != this.oauth2State)
{
// The state in the response doesn't match the state in the request.
return;
}
this.AccessToken = result.AccessToken;
this.Result = true;
}
catch (ArgumentException)
{
// There was an error in the URI passed to ParseTokenFragment
}
finally
{
e.Cancel = true;
this.Close();
}
}
I've been fighting against this for hours and I'm starting to see the things a little cloudy at this point.
This is the tutorial I used, but I'm not moving forward. I would really appreciate any help!
EDIT: I finally made some steps forward. I changed the line which contains
Uri authorizeUri2 = DropboxOAuth2Helper.GetAuthorizeUri(appKey);
Now I'm showing the generated access token on the WebClient! Bad part comes when trying to get it (it gets inside the if) and it gets generated every time I ask the user for permission, so it gets overwrited.
EDIT 2: I noted the token I get generated on the browser is somehow malformed. I try to manually change it hardcored when I'm debugging and I get an exception when an AuthException when creating the DropboxClient object :( What the hell!
As Greg stated, the solution was using the event Browser_Navigated. Looks like the version of the embedded IE my Visual Studio (2015) uses didn't notice that if it's a redirect, it won't launch the event BrowserNavigating.
I am building a Windows c# app that needs to upload files to DropBox. Basically I have everything I need for my app(app secret and app key), but I need to have the client tokens saved to my sql DB for future use. According to Dropbox I am unable to save user login info which is good, but finding a good lib is getting tough.I have tried many different DropBox based libraries but run across the following issues:
SharpBox: seems easy enough to use, but need some kind of deserializer to save the client key and client secret anywhere.
OAuth2 Authorizer: Not enough documentation that I can find, in order for me to actually implement this.
DropNet: This is one that looked promising. It's async and looked good, but again I can't find an example of how to perform the auth function and save the variables to a file/DB/Reg/ or anything.
DropBox.API: This is the method that I currently use and it's working. Problem is it's not Async and requires .NET 4.5. I was ok with all the downs but lately found that's it's very touchy about different versions of JSON and other libraries.
I was hoping someone could give me some assistance in getting any of the above OAUTH libs actually working, Just to get the 3 legged auth process working.
UPDATE::
ok so i am going to include some of the code that I am using at the moment, that uses dropbox.api:
// Get Oauth Token
private static OAuthToken GetAccessToken()
{
string consumerKey = "mykey";
string consumerSecret = "myseceret";
var oauth = new OAuth();
var requestToken = oauth.GetRequestToken(new Uri(DropboxRestApi.BaseUri), consumerKey, consumerSecret);
var authorizeUri = oauth.GetAuthorizeUri(new Uri(DropboxRestApi.AuthorizeBaseUri), requestToken);
Process.Start(authorizeUri.AbsoluteUri);
MessageBox.Show("Once Registration is completed Click OK", "Confirmation");
return oauth.GetAccessToken(new Uri(DropboxRestApi.BaseUri), consumerKey, consumerSecret, requestToken);
}
// Complete Oauth function and write to file
private void button5_Click(object sender, EventArgs e)
{
DialogResult result1 = MessageBox.Show("Please register for dropbox before continuing with authentication. The authorization process will take 1 minute to complete. During that time the backup utility window will be unresponsive. Click yes if you are ready to begin the authorization. HAVE YOU REGISTERED FOR DROPBOX YET?", "DO YOU HAVE A DROPBOX ACCOUNT?", MessageBoxButtons.YesNo);
if (result1 == DialogResult.Yes)
{
try
{
u_w.Enabled = false;
var accesstoken = GetAccessToken();
StringBuilder newFile = new StringBuilder();
string temptoken = "";
string tempsecret = "";
string tempprovider = "";
string tempstatus = "";
string[] file = System.IO.File.ReadAllLines(#"C:\cfg\andro_backup.ini");
foreach (string line in file)
{
if (line.Contains("dbkey:"))
{
temptoken = line.Replace("dbkey:", "dbkey:" + accesstoken.Token);
newFile.Append(temptoken + "\r\n");
continue;
}
if (line.Contains("dbsecret:"))
{
tempsecret = line.Replace("dbsecret:", "dbsecret:" + accesstoken.Secret);
newFile.Append(tempsecret + "\r\n");
continue;
}
if (line.Contains("Provider:"))
{
tempprovider = line.Replace("Provider:", "Provider:DropBox");
newFile.Append(tempprovider + "\r\n");
continue;
}
if (line.Contains("Status:"))
{
tempstatus = line.Replace("Status:", "Status:Connected");
newFile.Append(tempstatus + "\r\n");
continue;
}
newFile.Append(line + "\r\n");
}
System.IO.File.WriteAllText(#"C:\cfg\andro_backup.ini", newFile.ToString());
MessageBox.Show("Completed Backup Provider Setup", "Provider Setup Complete");
Configuration.Reload();
The Above works at the moment and I can upload, download files. The issue is it's not Async and I would like to attempt to stay within the .NET 4.0 if possible, this code requires 4.5
Trying to do the same thing with dropnet, I am unable to get it to work at all even using the examples he has given on the page located here https://github.com/dkarzon/DropNet.
I attempted to look at the demos he has on there as well , but they explaing having the user login everytime to perform any functions, where I need the app to be authorized so it can do it's deeds when it needs to. As far as the code I am using for drop net, I literally just copied and pasted what he had there, just to even see if I can get it to connect and still no go.
If you are using DropNet similar to the examples all you need to do is save the return object from the GetAccessToken method. That returns an instance of a UserLogin object which has the Token and secret on it. Or if you are using the async methods for it then the callback parameter.
Checkout the sample here:
https://github.com/dkarzon/DropNet/blob/master/DropNet.Samples/DropNet.Samples.WP7/MainPage.xaml.cs#L69
Post the code you are using for it so I can give you a better explanation for it.
A quick project I've been asked to knock together doesn't need crazy security, so, I've implemented a simple login screen that checks the Username & PW against the db.
User u = new User();
if (u.AuthenticateUser(txtUsername.Text, txtPassword.Text))
Session.Add("UserSeshAuthenticated", true);
Response.Redirect("Dashboard.aspx");
All the other pages share a MasterPage and in the Page_Load event:
if ((Session["UserSeshAuthenticated"] == null) || ((bool)Session["UserSeshAuthenticated"] == false))
{
fw.Write("UserSeshAuthenticated has been lost or something");
string path = HttpContext.Current.Request.Url.AbsolutePath;
Response.Redirect("Login.aspx?retpath=" + path);
}
else
{
lblLoggedInUsername.Text = Session["UserSeshAuthenticated"].ToString();
}
This all works very well on my development machine, but when I've published it to my server, by the time my MasterPage loads, it has lost the session variables.
Can anyone help ?... I'm supposed to have it live this afternoon & I didn't think I'd run into this problem !!!
Any help appreciated. Thanks a lot.
In your login code, you add "UserSeshAuthenticated" to the session, but not the User object. If the function u.AuthenticateUser() adds a copy of itself into the Session, that could be your problem. Try adding that in your result block instead. Like this:
User u = new User();
if (u.AuthenticateUser(txtUsername.Text, txtPassword.Text))
{
Session.Add("UserSeshAuthenticated", true);
Session.Add("oUser", u);
Response.Redirect("Dashboard.aspx");
}