I'm making an application in Unity which uses the phone's camera and the user's location. I want these permission popups to be shown to the user, after they've read why I want them to give permission. So pressing the "Accept" button in the app should check if the app has a certain permission and if not: ask that permission.
So in short, what I need is:
- A way to check if the app has a specific permission
- A way to trigger the permission popup
- (Nice to have:) A way to check if permission was granted or denied in said popup
I've already built exactly this for Android, as android provides ways to do so.
After googling, I've found that iOS will prompt permissionpopups when the app starts a certain service that requires an ungranted permission. This means I could simply start up the location service or camera to check if the app has these permissions. I think this is a dirty fix, though, as it requires the app to start services that are not needed at that time.
Welcome to StackOverflow!
You can use this library: https://github.com/jamesmontemagno/PermissionsPlugin
If you want to retrieve the location permission, you can use this code:
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status != PermissionStatus.Granted)
{
if(await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Location))
{
await DisplayAlert("Need location", "Gunna need that location", "OK");
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
//Best practice to always check that the key exists
if(results.ContainsKey(Permission.Location))
status = results[Permission.Location];
}
if (status == PermissionStatus.Granted)
{
var results = await CrossGeolocator.Current.GetPositionAsync(10000);
LabelGeolocation.Text = "Lat: " + results.Latitude + " Long: " + results.Longitude;
}
else if(status != PermissionStatus.Unknown)
{
await DisplayAlert("Location Denied", "Can not continue, try again.", "OK");
}
}
catch (Exception ex)
{
LabelGeolocation.Text = "Error: " + ex;
}
Related
I have an upload method that looks like this
public ActionResult UploadImage(int? id)
{
if (id == null)
return HttpNotFound();
Component c = db.Components.Find((int)id);
HttpPostedFileBase photo = Request.Files["image"];
if (photo != null && photo.ContentLength > 0)
{
var file = IGT.imagePath + "\\Components\\";
//bool exists = System.IO.Directory.Exists(Server.MapPath(file));
//if (!exists)
// System.IO.Directory.CreateDirectory(Server.MapPath(file));
var filename = file + id.ToString() + ".jpg";
if (!System.IO.Directory.Exists(file))
{
System.IO.Directory.CreateDirectory(file);
}
photo.SaveAs(filename);
c.Image_Url = IGT.baseUrl + "/Content/images/Components/" + id.ToString() +".jpg";
db.SaveChanges();
}
But I receive the error at photo.SaveAs(filename); saying
System.UnauthorizedAccessException: 'Access to the path 'C:\Users\chris\Source\Repos\inventory2.0\PIC_Program_1.0\Content\images\Components\498.jpg'
is denied.'
Why is this and how can I fix it?
Whatever user is executing that code, does not have permission to write to that file path. If you go to C:\Users\chris\Source\Repos\inventory2.0\PIC_Program_1.0\Content\images\Components, right click, properties, Security tab, you will see the users that have permissions and what those permissions are. You can add or edit your users permissions there.
I think the problem is your application user don't have permission to access your the folder. If you are testing this in VS IIS express, then you should grant permission for your current user.
However, if you are receiving this error message from IIS Server. Then you should grant permission for application pool identity(IIS Apppool\apppoolname).
Process monitor can help you fix access denied error all the time. You just need to create a filter for Result ="access is denied". Then it will tell you who and what permission are required.
https://learn.microsoft.com/en-us/sysinternals/downloads/procmon
I want to display a custom message to the user for app permission. I am using Plugin.Permissions for App permission. When i run the current code and run application this popup message display Allow {App Name} to access this device location?. Below is the function currently i am using.
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}
Thanks for your help and comments
Sadly there is no way to customize the text in the permission dialogs.
These are system dialogs and the app has no control over their content.
Quote from https://developer.android.com/training/permissions/requesting#perm-request
When your app receives PERMISSION_DENIED from checkSelfPermission(), you need to prompt the user for that permission. Android provides several methods you can use to request a permission, such as requestPermissions(), as shown in the code snippet below. Calling these methods brings up a standard Android dialog, which you cannot customize.
How this is displayed to the user depends on the device Android version as well as the target version of your application, as described in the Permissions Overview.
I'm using Parse and their .NET SDK (WP8) to login into my application with a Facebook account.
I wrote :
IEnumerable<string> permissions = new List<string>() {"user_about_me"};
try
{
ParseUser user = await ParseFacebookUtils.LogInAsync(browser, permissions);
}
catch (Exception e)
{
System.console.Write("Error {0}", e.ToString());
}
But I catching an exception : "A task was canceled"
I registered my app on http://developers.facebook.com, copy and paste everything (and Product ID from my app manifest).
Do you know what am I missing ?
I have a fairly odd requirement to be able to impersonate a user, when I'm already impersonating another, using C#.
I'm writing an app to allow the management of Active Directory users. This app will provide the ability for anyone in the company to view and maintain certain details about themselves (some of which will not actually be saved to Active Directory, but some of which will), for managers to be able to view and maintain details about their team, and for HR to be able to view and maintain details about anyone.
For obvious reasons I don't want to develop or test this against the live domain. We have recently ported all users over to this domain from another domain, which means I can actually test against the old domain without affecting anything. However, to enable me to do this I have to impersonate my old account on the old domain, which I do on loading the application.
Although for me everything will work fine as I'm setup as a domain admin, going forward obviously not all users will be domain admins, and won't be able to write to AD under their own account, and therefore we have another domain admin user setup specifically for this application, whenever data needs to be saved to AD that user is impersonated. This was working great before when I was testing against an Active Directory I'd setup on a virtual machine because I was logging onto the local domain, however that didn't allow me to step through the code in Visual Studio so debugging was slow, and hence I've stopped using that virtual machine and am using this old domain. Now I'm already impersonating another user (i.e. my old domain account), when it then tries to impersonate the domain admin user it fails with an "System.Security.SecurityException: Access is denied." exception. The line this fails on is just writing out some debugging information using "WindowsIdentity.GetCurrent().Name".
If I change my code so I'm actually logging in using the new domain admin rather than my old account, the first time it goes through it logs in successfully (so the credentials are correct), however when it then goes through and tries to do the same again to write to AD it fails with the above exception. Therefore I think it must be a problem with trying to do a nested impersonate.
Is it possible to do a nested impersonate?
Below is the code I'm using:
private static WindowsImpersonationContext ImpersonateUser(out string result, string sUsername,
string sDomain, string sPassword)
{
// initialize tokens
var pExistingTokenHandle = new IntPtr(0);
var pDuplicateTokenHandle = new IntPtr(0);
// if domain name was blank, assume local machine
if (sDomain == "")
{
sDomain = Environment.MachineName;
}
try
{
result = null;
const int logon32ProviderDefault = 0;
// create token
const int logon32LogonInteractive = 2;
// get handle to token
var bImpersonated = LogonUser(sUsername, sDomain, sPassword,
logon32LogonInteractive,
logon32ProviderDefault,
ref pExistingTokenHandle);
// did impersonation fail?
if (!bImpersonated)
{
var nErrorCode = Marshal.GetLastWin32Error();
result = "LogonUser() failed with error code: " + nErrorCode + "\r\n";
}
// Get identity before impersonation
result += string.Format("Before impersonation: {0}\r\n", WindowsIdentity.GetCurrent().Name);
var bRetVal = DuplicateToken(pExistingTokenHandle, (int)SecurityImpersonationLevel.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (bRetVal)
{
// create new identity using new primary token
var newId = new WindowsIdentity(pDuplicateTokenHandle);
var impersonatedUser = newId.Impersonate();
// check the identity after impersonation
result += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";
return impersonatedUser;
}
else
{
var nErrorCode = Marshal.GetLastWin32Error();
CloseHandle(pExistingTokenHandle); // close existing handle
result += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n";
return null;
}
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
{
CloseHandle(pExistingTokenHandle);
}
if (pDuplicateTokenHandle != IntPtr.Zero)
{
CloseHandle(pDuplicateTokenHandle);
}
}
}
When this is called for the nested impersonation which fails, "bImpersonated" is actually "true", as is bRetVal, which suggests its worked, however when it gets to "WindowsIdentity.GetCurrent().Name" it fails with the exception above.
I hope this makes sense, and would appreciate any assistance.
I have a windows service which polls for a specific folder for creation of new files. This works fine when the folder is in one of the local drives such as C: or D:
The service fails to find a folder on a mapped drive.
Here is the code which does the checking for folder exist before polling:
System.Security.Principal.WindowsIdentity userIdentity =
System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal =
new System.Security.Principal.WindowsPrincipal(userIdentity);
MappedDriveResolver mdr = new MappedDriveResolver();
if (mdr.isNetworkDrive(folderPath))
{
LoggingAppWrapper.LogDeveloperMessage(folderPath + " is on a Mapped drive", 1, TraceEventType.Information, string.Empty);
}
MappedDriveResolver is a class that I found hereHow do I determine a mapped drive's actual path?
The code in that link works fine from a simple console application, but fails when it is part of windows service.
Any suggestions as to what has to be done for the code to work for a windows service?
Regards.
I would recommend you configure your service to use UNC paths for folders not on the server running the service.
Mapped drives are a usability feature for users and as such they are specific to that users profile/environment. Meaning, when you login you may have a drive X: that is mapped to \\server1\share1 but when I login my drive X: could be mapped to \\server2\share2 instead. The actual mapping process is either saved as part of your profile with the "Reconnect at logon" or is handled by a logon script.
You need to check what account the service is running under and make sure that mapped drive exists for that user environment (This might help How to map a network drive to be used by a service).
Edit:
The reason your console application works and the service doesn't is because of the differences between the environment they are running in.
To illustrate this, take this console application, compile it and then run it as a Schedule Task. Set the "path" variable to be a mapped drive that your user can access.
static void Main(string[] args) {
MappedDriveResolver mdr = new MappedDriveResolver();
string logfile;
string path = #"I:\";
string[] files;
// Write out "log" file to where this is running from
logfile = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
logfile = Path.Combine(logfile, "log.txt");
using (StreamWriter sw = new StreamWriter(logfile, true)) {
try {
sw.WriteLine("Checking path " + path);
if (mdr.isNetworkDrive(path)) {
sw.WriteLine("Network Drive: Yes");
} else {
sw.WriteLine("Network Drive: No");
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Resolve path " + path);
string newpath = mdr.ResolveToUNC(path);
sw.WriteLine("Resolved path " + newpath);
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Get file list from " + path);
files = Directory.GetFiles(path);
if (files == null || files.Length == 0) {
sw.WriteLine("No files found");
} else {
sw.WriteLine(string.Format("Found {0} files.", files.Length));
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
sw.Flush();
sw.Close();
}
}
Note: This is with the Windows 7 Task Scheduler
Test 1: Just run the app by double-clicking on it.
Result: Success
Test 2: Configure scheduled task to run as your user account with "Run only when user is logged on"
Result: Success
Test 3: Configure scheduled task to run as your user account with "Run whether user is logged on or not"
Result: Exceptions
Test 4: Configure schedule task to run as "Local Service" account.
Result: Exceptions
Test 1 & 2 work because they are using the currently logged in user environment including the mapped drives that are part of it.
Test 3 & 4 fail because they have their own user environment created for them, which does not have any mapped drives configured. It escapes me at the moment what the differences there are, but an "interactive" and "non-interactive" environment are different in some significant ways.