Sending the unique phone id as an email - windows-phone-7

I try to create an app that allows the user to register himself for my service.
The problem is that it is very important that i can limit each user to a very single account
i figured out I could probably do this with the Phone unique id and the windows live id
i also figured out how to get These within the app , but now my problem is how to get them to me!
Can anyone help me on how to send the phone id with the desired username to my email address ?
Thank you
EDIT
I use this code to get the needed values
public static class ExtendedPropertyHelper
{
private static readonly int ANIDLength = 32;
private static readonly int ANIDOffset = 2;
public static string GetManufacturer()
{
string result = string.Empty;
object manufacturer;
if (DeviceExtendedProperties.TryGetValue("DeviceManufacturer", out manufacturer))
result = manufacturer.ToString();
return result;
}
//Note: to get a result requires ID_CAP_IDENTITY_DEVICE
// to be added to the capabilities of the WMAppManifest
// this will then warn users in marketplace
public static byte[] GetDeviceUniqueID()
{
byte[] result = null;
object uniqueId;
if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId))
result = (byte[])uniqueId;
return result;
}
// NOTE: to get a result requires ID_CAP_IDENTITY_USER
// to be added to the capabilities of the WMAppManifest
// this will then warn users in marketplace
public static string GetWindowsLiveAnonymousID()
{
string result = string.Empty;
object anid;
if (UserExtendedProperties.TryGetValue("ANID", out anid))
{
if (anid != null && anid.ToString().Length >= (ANIDLength + ANIDOffset))
{
result = anid.ToString().Substring(ANIDOffset, ANIDLength);
}
}
return result;
}
}
Now i need to store thes in variables ( what i cant really get to work ) and then send them to my php script which extracts them
in addition to this i need to ask the user to enter his email address and include this in the POST too ,
can you help?

You can get DeviceExtendedProperties.DeviceUniqueId from Microsoft.Phone.Info namespace.
Don't forget to declare in WMAppManifest.xml
like this:
<Capabilities>
<Capability Name="ID_CAP_IDENTITY_DEVICE"/>
<Capability Name="ID_CAP_IDENTITY_USER"/>
</Capabilities>
Link to msdn here
Then, you can send this id to your e-mail:
var emailComposeTask = new EmailComposeTask
{
To = "your-email#domiain.com",
Subject = "Test Message using EmailComposeTask",
Body = deviceId
};
emailComposeTask.Show();
But this will open an-email client, and I don't thik that user will be so kind to send you an email. So, you'd better send a POST request to your server
private void Button_Click(object sender, RoutedEventArgs e)
{
//collect all data you need:
var deviceId = Convert.ToBase64String(ExtendedPropertyHelper.GetDeviceUniqueID());
var userName = ExtendedPropertyHelper.GetWindowsLiveAnonymousID();
var manufatcurer = ExtendedPropertyHelper.GetManufacturer();
//create request string
//[see the explanation on MSDN][2]
var requestUrl = string
.Format("http://myPageUrlAddress.com/script.aspx?deviceid={0}&user={1}&manufacturer={2}",
deviceId, userName, manufatcurer);
System.Uri myUri = new System.Uri(requestUrl);
//create a request instance
HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(myUri);
myRequest.Method = "POST";
myRequest.ContentType = "application/x-www-form-urlencoded";
//and it will be sent.
//Also you need to create GetRequestStreamCallback method to
//handle server responce.
myRequest.BeginGetRequestStream(new
AsyncCallback(GetRequestStreamCallback), myRequest);
}
//this method is empty. You can show tha dialog box about successful sending.
public void GetRequestStreamCallback(IAsyncResult result) { ; }
What about e-mail - just create a TextBox on the same Page, and save user input to a variable.

If "my service" is a web service, then you could use the web service instead of the mail system.
In either case you can use Convert.ToBase64String(phoneId) to convert the phone id to a string.
To send strings via mail from WP7 you need to use EmailComposeTask.

Related

Xamarin open id login with Google

I'm setting up an open id login for Google en Microsoft and use the IdentityModel.OidcClient. I've been able to make it work for Microsoft, but the Google login doesn't return any tokens (they are all null). I followed [this tutorial][1]. To make the Microsoft login work, I needed to add ProviderInformation.UserInfoEndpoint to the OidcClientOptions. This was not mentioned in the tutorial.
I hoped the same trick would arrange things for Google too, but it didn't. So now I'm stuck with the Google login and I don't see what's missing. I hope someone else can give me that last push in the back.
One thing I noticed and find quite strange: if I add the client secret to my OidcClientOptions, I don't get a token back for the Microsoft login. If I remove it, all tokens (identity token, acces token etc) are returned.
This is the code I used to create the OidcClient object with all the options:
private OidcClient CreateOidcClient(string authorityUrl, string clientId, string scope, string redirectUrl, string issuerName, string tokenEndpoint, string authorizeEndpoint, string userInfoEndPoint, string? clientSecret = null)
{
var options = new OidcClientOptions
{
Authority = authorityUrl,
ClientId = clientId,
ClientSecret = clientSecret,
Scope = scope,
RedirectUri = redirectUrl,
Browser = new WebAuthenticatorBrowser(),
ProviderInformation = new ProviderInformation
{
IssuerName = issuerName,
KeySet = new JsonWebKeySet(),
TokenEndpoint = tokenEndpoint,
AuthorizeEndpoint = authorizeEndpoint,
UserInfoEndpoint = userInfoEndPoint,
}
};
var oidcClient = new OidcClient(options);
return oidcClient;
}
This is the code I use when you click the "Sign in with Google" button:
private async Task GoogleLogIn()
{
OidcClient oidcClient = CreateOidcClient(
GoogleConfiguration.AuthorizeUrl,
GoogleConfiguration.ClientId,
GoogleConfiguration.Scope,
GoogleConfiguration.RedirectUrl,
GoogleConfiguration.IssuerName,
GoogleConfiguration.TokenEndpoint,
GoogleConfiguration.AuthorizeEndpoint,
GoogleConfiguration.UserInfoEndpoint,
GoogleConfiguration.ClientSecret
);
LoginResult loginResult = await oidcClient.LoginAsync(new LoginRequest());
}
And finally the GoogleConfiguration:
public static class GoogleConfiguration
{
public static readonly string AuthorizeUrl = "https://accounts.google.com/o/oauth2/v2/auth";
public static readonly string ClientId = "XXXXXXXXX";
public static readonly string Scope = "openid profile email";
public static readonly string RedirectUrl = "XXXXXXXXX:/oauth2redirect";
public static readonly string IssuerName = "accounts.google.com";
public static readonly string TokenEndpoint = "https://www.googleapis.com/oauth2/v3/certs";
public static readonly string AuthorizeEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
public static readonly string UserInfoEndpoint = "https://openidconnect.googleapis.com/v1/userinfo";
public static readonly string ClientSecret = "XXXXXXXXX";
}
This is the WebAuthenticationCallbackActivity class:
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTask)] // or SingleTop?
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "data_scheme_microsoft")]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "data_scheme_google")]
public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
{
}
I receive following unclear error when the loginResult gets returned:
Error redeeming code: Not Found / no description
Any help is very much appreciated! If you need additional information, just let me know.
[1]: https://mallibone.com/post/xamarin-oidc
I am not an expert, but lately succeeded in making the same sample code work against Google.
Along the way, I have got:
Error redeeming code: Unauthorized / Unauthorized
But then I realised that I am setting client secret that I had got from a different identity provider but Google. Google does not give a client secret when you create a client ID, does it?
I fixed it and now am able to get tokens.
I finally figured it out: some credentials had been changed while I was working on this project. I didn’t notice because the old and new credentials looked very very very similar. A simple copy & paste did the trick.

How to get user context during Web Api calls?

I have an web front end calling an ASP Web Api 2 backend. Authentication is managed with ASP Identity. For some of the controllers I'm creating I need to know the user making the call. I don't want to have to create some weird model to pass in including the user's identity (which I don't even store in the client).
All calls to the API are authorized using a bearer token, my thought is the controller should be able to determine the user context based on this but I do not know how to implement. I have searched but I don't know what I'm searching for exactly and haven't found anything relevant. I'm going for something like...
public async Task<IHttpActionResult> Post(ApplicationIdentity identity, WalkthroughModel data)
Update
I found the below which looked very promising... but the value is always null! My controller inherits from ApiController and has an Authorize header.
var userid = User.Identity.GetUserId();
Update 2
I have also tried all of the solutions in Get the current user, within an ApiController action, without passing the userID as a parameter but none work. No matter what I am getting an Identity that is valid and auth'd, but has a null UserID
Update 3
Here's where I'm at now.
[Authorize]
[Route("Email")]
public async Task<IHttpActionResult> Get()
{
var testa = User.Identity.GetType();
var testb = User.Identity.GetUserId();
var testc = User.Identity.AuthenticationType;
var testd = User.Identity.IsAuthenticated;
return Ok();
}
testa = Name: ClaimsIdentity,
testb = null,
testc = Bearer,
testd = true
The user is obviously authenticated but I am unable to retrieve their userID.
Update 4
I found an answer, but I'm really unhappy with it...
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string username = identity.Claims.First().Value;
That gets me the username without any db calls but it seems very janky and a pain to support in the future. Would love if anyone had a better answer.
What if I need to change what claims are issued down the road? Plus any time I actually need the user's id I have to make a db call to convert username to ID
A common approach is to create a base class for your ApiControllers and take advantage of the ApplicationUserManager to retrieve the information you need. With this approach, you can keep the logic for accessing the user's information in one location and reuse it across your controllers.
public class BaseApiController : ApiController
{
private ApplicationUser _member;
public ApplicationUserManager UserManager
{
get { return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
}
public string UserIdentityId
{
get
{
var user = UserManager.FindByName(User.Identity.Name);
return user.Id;
}
}
public ApplicationUser UserRecord
{
get
{
if (_member != null)
{
return _member ;
}
_member = UserManager.FindByEmail(Thread.CurrentPrincipal.Identity.Name);
return _member ;
}
set { _member = value; }
}
}
I use a custom user authentication (I dont use AspIdentity because my existing user table fields was far different from IdentityUser properties) and create ClaimsIdentity passing my table UserID and UserName to validate my bearer token on API calls.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
User user;
try
{
var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
_service = scope.Resolve<IUserService>();
user = await _service.FindUserAsync(context.UserName);
if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
catch (Exception ex)
{
context.SetError("invalid_grant", ex.Message);
return;
}
var properties = new Dictionary<string, string>()
{
{ ClaimTypes.NameIdentifier, user.UserID.ToString() },
{ ClaimTypes.Name, context.UserName }
};
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
properties.ToList().ForEach(c => identity.AddClaim(new Claim(c.Key, c.Value)));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(properties));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
And how I use the ClaimsIdentity to retrieve my User table details on User ApiController Details call.
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("Details")]
public async Task<IHttpActionResult> Details()
{
var user = await _service.GetAsync(RequestContext.Principal.Identity.GetUserId<int>());
var basicDetails = Mapper.Map<User, BasicUserModel>(user);
return Ok(basicDetails);
}
Notice the
ClaimTypes.NameIdentifier = GetUserId() and ClaimTypes.Name = GetUserName()

Passing a variables in C#

I am trying to pass a variable that identifies a staff member from their login details to the next screen to populate the Tester ID box.
Would I be better using a global variable that is then read when the next screen is set up or would I be better to put it into a variable and send it to the next screen?
The login code sits as follows:
public Login()
{
InitializeComponent();
}
private void LoginButton_Click(object sender, EventArgs e)
{
String Username1 = StaffUsername.Text;
String Password1 = StaffPassword.Text;
String HardUser = "Test";
String HardPass = "Merlin123";
if (Username1 == "" && Password1 == "")
{
MessageBox.Show("Please Enter Login Id and Password");
}
else
{
if (Username1.Equals(HardUser) && Password1.Equals(HardPass))
{
this.Hide();
AddingClients M1 = new AddingClients();
M1.Show();
}
else{
this.Hide();
Login Lg = new Login();
Lg.Show();
MessageBox.Show("Incorrect Username or Password Entered");
}
}
}
}
}
I am using a hardcoded username and password for now, but in the actual program, I would have this call on a database and compare the username and the password and then go through to the next screen.
Would lit be better to have a global variable that the login action throws over to the next screen or would it be easier having a variable that the next screen reads and then populates the text box required? How would I go about this?
Thanks
The way you do this is to use the Thread.CurrentPrincipal.
Once the user is confirmed to be who they say they are, you can do:
private static void SignUserIn(string userName)
{
GenericIdentity identity = new GenericIdentity(userName, null);
Thread.CurrentPrincipal = new GenericPrincipal(identity);
}
Then whenever you need the userName, you use Thread.CurrentPrincipal.Identity.Name.
To extend this a little further, its probably best to abstract this a little bit, so you can swap in and out providers e.g. you might want to use Windows Authentication.
So you could do it like this:
public interface IAuthenticator
{
bool IsValidUser ( string username, string password );
IPrincipal SignInUser ( string username );
void SignOutCurrentUser();
}
public class DbAuthenticator : IAuthenticator
{
public bool IsValidUser ( string username, string password )
{
// Check user here and return bool if valid
}
public void SignInUser(string userName, string[] roles = null)
{
GenericIdentity identity = new GenericIdentity(userName, roles);
Thread.CurrentPrincipal = new GenericPrincipal(identity);
return Thread.CurrentPrincipal;
}
public void SignOutUser()
{
Thread.CurrentPrincipal = WindowsPrincipal.GetCurrent();
}
}
Then in your code, inject the authenticator using some sort of DI pattern. So MEF would be like this:
[Export(typeof(IAuthenticator))]
public interface IAuthenticator { }
And in your form:
[Import]
internal IAuthenticator authenticator;
private static void SignUserIn(string userName)
{
authenticator.SignUserIn(username);
}
You should have a User object and pass it to other pages and functions. That way they become more testable.
But you also need to store the object somewhere globally so you can retrieve the currently logged in user when needed. The problem with that is that piece of code then depends on that user storage existing/working, but if it's only one place it's okay.
PS: your title should be: pass the user on or store globally?

Post Binary array to Web API Controller

I am trying to POST form data which consists of few string variable and binary array.
Below is the Model for the form data.
public class FileModel
{
public string Path { get; set; }
public byte[] File { get; set; }
}
Below is my Web API Controller.
[Route("")]
public IHttpActionResult Post([FromBody]FileModel media)
{
// Can I use ??
byte[] requestFile = media.File;
string requestFilePath = media.Path;
//Process the above variables
return Ok();
}
I would like to know Can I use the following code to de-serialize the following code snippet to to read the values from the JSON payload including the binary data?
byte[] requestFile = media.File;
string requestFilePath = media.Path;
If Yes, Do I need to define any formatter class to get it working?
I normally use POSTMAN to test my RESTful endpoints.
Is it possible to use POSTMAN still to POST binary array? May be not need to write my own client
You'll need to use a serializer to serialize complex objects (multiple fields) as content for a Http Request.
For your code snippet to read the object from the content you can use this:
var requestContent = Request.Content.ReadAsAsync<FileModel>(GetJsonSerializer()).Result;
Here's the serializer boilerplate code.
private JsonMediaTypeFormatter GetJsonSerializer()
{
JsonSerializerSettings settings = new JsonSerializerSettings()
{
PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All,
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All
};
return new JsonMediaTypeFormatter() { SerializerSettings = settings };
}
I'm not sure how to use POSTMAN to test this. A simple .net client would be:
var Client = new HttpClient();
Client.BaseAddress = new Uri("localhost"); //whatever your endpoint is
FileModel objectToSend = new FileModel();
var objectContent = new ObjectContent<FileModel>(objectToSend, GetJsonSerializer() );
var response = Client.PostAsync("uri", objectContent);
You are able to use POSTMAN to test binary file input. Selecting the body tab, you can then pick the radio button "binary" and then choose file.

How to know the download link of a windows phone 8 application

I'm developing windows phone 8 application. In which I have to share the application's download link on Facebook and Twitter.
Before publishing the application on to the windows phone store, How could I know the download link of the application.
Because we have to implement the share functionality before publishing the application.
I'm looking forward for your responses.
Thanks & Regards,
Suresh
Basically your application download link format is as follow :
http://windowsphone.com/s?appid=<ApplicationId>
with <ApplicationId> is value of ProductID attribute of App element in WMAppManifest.xml file. That ProductID in WMAppManifest.xml will be overridden when you submit the Apps to Marketplace, so avoid hardcoding it. This post demonstrates how to get <ApplicationId> from manifest file as well as how to share it using Microsoft.Phone.Tasks.ShareLinkTask.
UPDATE :
To summarize, create a helper class to read ApplicationID from WMAppManifest.xml file :
public class DeepLinkHelper
{
private const string AppManifestName = "WMAppManifest.xml";
private const string AppNodeName = "App";
private const string AppProductIDAttributeName = "ProductID";
public static string BuildApplicationDeepLink()
{
var applicationId = Guid.Parse(GetManifestAttributeValue(AppProductIDAttributeName));
return BuildApplicationDeepLink(applicationId.ToString());
}
public static string BuildApplicationDeepLink(string applicationId)
{
return #"http://windowsphone.com/s?appid=" + applicationId;
}
public static string GetManifestAttributeValue(string attributeName)
{
var xmlReaderSettings = new XmlReaderSettings
{
XmlResolver = new XmlXapResolver()
};
using (var xmlReader = XmlReader.Create(AppManifestName, xmlReaderSettings))
{
xmlReader.ReadToDescendant(AppNodeName);
if (!xmlReader.IsStartElement())
{
throw new FormatException(AppManifestName + " is missing " + AppNodeName);
}
return xmlReader.GetAttribute(attributeName);
}
}
}
Then you can get/share download link this way :
new Microsoft.Phone.Tasks.ShareLinkTask()
{
Title = "My Application Deep Link",
Message = "My Application Deep Link",
LinkUri = new Uri(DeepLinkHelper.BuildApplicationDeepLink())
}.Show();
Credit to Pedro Lamas for all above codes.

Resources