By reading asmack source, when create a chat room and invite user to join, the message add a extendsion MUCUser.Invite .
public void invite(Message message, String user, String reason) {
// TODO listen for 404 error code when inviter supplies a non-existent JID
message.setTo(room);
// Create the MUCUser packet that will include the invitation
MUCUser mucUser = new MUCUser();
MUCUser.Invite invite = new MUCUser.Invite();
invite.setTo(user);
invite.setReason(reason);
mucUser.setInvite(invite);
// Add the MUCUser packet that includes the invitation to the message
message.addExtension(mucUser);
connection.sendPacket(message);
}
I use message.getExtension( "x","http://jabber.org/protocol/muc#user"), but it return DefaultPacketExtension, not MUCUser.Invite. So I doubt how i can get inviter name.
Any help will be appreciative!
Using message.getBody(), it can get invite reason and content which contains inviter name. With subString(), I get the inviter name.
But I don't think it is a good solution, my doubt in the question is not solved。
Related
I want to get user email messages or tokens from Gmail in an Android application. How can I get a user's messages and token from Gmail? I need an example application.
You can use the example from here:
https://developers.google.com/gmail/api/quickstart/android
Later, instead request the labels you need to ask for messages so you need to update function 'getDataFromApi' to get messages :
private static final long MAX_RESULTS_PER_REQUEST = 20;
private void getDataFromApi() throws IOException {
List<String> labelsId = new ArrayList<>();
labelsId.add("INBOX");
ListMessagesResponse response=null;
response = mService.users().messages().list("me").setMaxResults(MAX_RESULTS_PER_REQUEST).setLabelIds(labelsId).execute();
List<Message> messages = response.getMessages();
for (Message message : messages) {
Message curMessage = mService.users().messages().get("me", message.getId()).execute();
System.out.println("cur message==>"+curMessage);
}
}
You can get this using Content Provider API of Gmail
The Android Gmail app starting in versions 2.3.6 (Froyo/Gingerbread)
and 4.0.5 (Honeycomb/ICS) includes a new Content Provider API that
third party developers can use to retrieve label information like name
and unread count, and stay updated as that information changes
To see an example of this API in action, check out the sample app.
I've been wracking my brain these past two days to try and understand how to use the authentication built into ASP.NET's WebAPI 2 using Google as an external authentication, and not being familiar with OAuth 2, I'm quite lost. I have followed this tutorial to set up the sign-in button on my Android client and send the "idToken" to the Web API. I've also followed this (now out of date) tutorial on setting up Google as an external login.
The problem happens when I try to send it I get {"error":"unsupported_grant_type"} as a response. Some other tutorials lead me to believe that the POST to mysite.com/token does not contain the correct data. This means I'm either building the request incorrectlyon the client, I'm somehow handling it incorrectly on the backend, I'm sending it to the wrong url, or I'm doing something entirely else wrong.
I found this SO answer which says to get a URL from /api/Accounts/ExternalLogins, but the sign-in button already gives me the access token that would supply to me (if I understand that correctly).
If someone could help me out here on what the exact process should be from start to finish, that would be amazing.
UPDATE: Okay, so here are some things that I've learned since I asked this question.
website.com/token URI is the redirect for the built in OAuth server in the WebAPI2 template. This is not useful for this particular problem.
The id_token is an encoded JWT token.
The website.com/signin-google URI is the redirect for normal Google login, but does not accept these tokens.
I may have to write my own AuthenticationFilter that uses the Google Client library to authorize through the Google API.
UPDATE 2: I'm still working on getting this AuthenticationFilter Implementation. Things seem to be going well at this point, but I'm getting stuck on some things. I've been using this example to get the token verification code, and this tutorial to get the AuthenticationFilter code. The result is a mix of both of them. I'll post it here as an answer once it's complete.
Here are my current problems:
Producing an IPrincipal as output. The verification example makes a ClaimPrincipal, but the AuthenticationFilter example code uses a UserManager to match the username to an existing user and returns that principal. The ClaimsPrincipal as created in the verification example directly does not auto-associate with the existing user, so I need to attempt to match some element of the claims to an existing user. So how do I do that?
I still have an incomplete idea of what a proper flow for this is. I'm currently using the Authentication header to pass my id_token string using a custom scheme: "goog_id_token". The client must send their id_token for every method called on the API with this custom AuthenticationFilter. I have no idea how this would usually be done in a professional environment. It seems like a common enough use case that there would be tons of information about it, but I haven't seen it. I have seen the normal OAuth2 flow, and since I'm only using an ID Token, and not an Access Token I'm a bit lost on what an ID Token is supposed to be used for, where it falls in a flow, and where it's supposed to live in an HTTP packet. And because I didn't know these things, I've kind of been making it up as I go along.
Wow, I did it. I figured it out. I... I can't believe it.
As metioned in my question Update 2, this code is assembled from Google's official API C# example and Microsoft's Custom AuthenticationFilter tutorial and code example. I'm going to paste the AuthorizeAsync() here and go over what each block of code does. If you think you see an issue, please feel free to mention it.
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
bool token_valid = false;
HttpRequestMessage request = context.Request;
// 1. Look for credentials in the request
//Trace.TraceInformation(request.ToString());
string idToken = request.Headers.Authorization.Parameter.ToString();
The client adds the Authorization header field with the scheme followed by a single space, followed by the id token. It looks something like Authorization: id-token-goog IaMS0m3.Tok3nteXt.... Putting the ID token in the body as given in the google documentation made no sense in this filter so I decided to put it in the header. For some reason it was difficult to pull custom headers from the HTTP packets so I just decided to use the Authorization header with a custom scheme followed by the ID token.
// 2. If there are no credentials, do nothing.
if (idToken == null)
{
Trace.TraceInformation("No credentials.");
return;
}
// 3. If there are credentials, but the filter does not recognize
// the authentication scheme, do nothing.
if (request.Headers.Authorization.Scheme != "id-token-goog")
// Replace this with a more succinct Scheme title.
{
Trace.TraceInformation("Bad scheme.");
return;
}
This whole point of a filter is to ignore requests that the filter doesn't govern (unfamiliar auth schemes, etc), and make judgement on requests that it's supposed to govern. Allow valid authentication to pass to the downstream AuthorizeFilter or directly to the Controller.
I made up the scheme "id-token-goog" because I had no idea if there was an existing scheme for this use case. If there is, somebody please let me know and I'll fix it. I guess it doesn't particularly matter at the moment as long as my clients all know the scheme.
// 4. If there are credentials that the filter understands, try to validate them.
if (idToken != null)
{
JwtSecurityToken token = new JwtSecurityToken(idToken);
JwtSecurityTokenHandler jsth = new JwtSecurityTokenHandler();
// Configure validation
Byte[][] certBytes = getCertBytes();
Dictionary<String, X509Certificate2> certificates =
new Dictionary<String, X509Certificate2>();
for (int i = 0; i < certBytes.Length; i++)
{
X509Certificate2 certificate =
new X509Certificate2(certBytes[i]);
certificates.Add(certificate.Thumbprint, certificate);
}
{
// Set up token validation
TokenValidationParameters tvp = new TokenValidationParameters()
{
ValidateActor = false, // check the profile ID
ValidateAudience =
(CLIENT_ID != ConfigurationManager
.AppSettings["GoogClientID"]), // check the client ID
ValidAudience = CLIENT_ID,
ValidateIssuer = true, // check token came from Google
ValidIssuer = "accounts.google.com",
ValidateIssuerSigningKey = true,
RequireSignedTokens = true,
CertificateValidator = X509CertificateValidator.None,
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
return identifier.Select(x =>
{
// TODO: Consider returning null here if you have case sensitive JWTs.
/*if (!certificates.ContainsKey(x.Id))
{
return new X509SecurityKey(certificates[x.Id]);
}*/
if (certificates.ContainsKey(x.Id.ToUpper()))
{
return new X509SecurityKey(certificates[x.Id.ToUpper()]);
}
return null;
}).First(x => x != null);
},
ValidateLifetime = true,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromHours(13)
};
This is all unchanged from the Google example. I have almost no idea what it does. This basically does some magic in creating a JWTSecurityToken, a parsed, decoded version of the token string, and sets up the validation parameters. I'm not sure why the bottom portion of this section is in it's own statement block, but it has something to do with the CLIENT_ID and that comparison. I'm not sure when or why the value of CLIENT_ID would ever change, but apparently it's necessary...
try
{
// Validate using the provider
SecurityToken validatedToken;
ClaimsPrincipal cp = jsth.ValidateToken(idToken, tvp, out validatedToken);
if (cp != null)
{
cancellationToken.ThrowIfCancellationRequested();
ApplicationUserManager um =
context
.Request
.GetOwinContext()
.GetUserManager<ApplicationUserManager>();
Get the user manager from the OWIN context. I had to dig around in context intellisense until I found GetOwinCOntext(), and then found that I had to add using Microsoft.Aspnet.Identity.Owin; in order to add the partial class that included the method GetUserManager<>().
ApplicationUser au =
await um
.FindAsync(
new UserLoginInfo(
"Google",
token.Subject)
);
This was the very last thing I had to fix. Again, I had to dig through um Intellisense to find all of the Find functions and their overrides. I had noticed from the Identity Framework-created tables in my database that there is one called UserLogin, whose rows contain a provider, a provider key, and a user FK. The FindAsync() takes a UserLoginInfo object, which contains only a provider string and a provider key. I had a hunch that these two things were now related. I had also recalled that there was a field in the token format that included a key-looking field that was a long number that started with a 1.
validatedToken seems to be basically empty, not null, but an empty SecurityToken. This is why I use token instead of validatedToken. I'm thinking there must be something wrong with this, but since the cp is not null, which is a valid check for a failed validation, it makes enough sense that the original token is valid.
// If there is no user with those credentials, return
if (au == null)
{
return;
}
ClaimsIdentity identity =
await um
.ClaimsIdentityFactory
.CreateAsync(um, au, "Google");
context.Principal = new ClaimsPrincipal(identity);
token_valid = true;
Here I have to create a new ClaimsPrincipal since the one created above in validation is empty (apparently that's correct). Took a guess on what the third parameter of CreateAsync() should be. It seems to work that way.
}
}
catch (Exception e)
{
// Multiple certificates are tested.
if (token_valid != true)
{
Trace.TraceInformation("Invalid ID Token.");
context.ErrorResult =
new AuthenticationFailureResult(
"Invalid ID Token.", request);
}
if (e.Message.IndexOf("The token is expired") > 0)
{
// TODO: Check current time in the exception for clock skew.
Trace.TraceInformation("The token is expired.");
context.ErrorResult =
new AuthenticationFailureResult(
"Token is expired.", request);
}
Trace.TraceError("Error occurred: " + e.ToString());
}
}
}
}
The rest is just exception catching.
Thanks for checking this out. Hopefully you can look at my sources and see which components came from which codebase.
Authentication and app engine, there is a lot to be read about it, but a lot seems to be outdated!
Even the google pages https://developers.google.com/appengine/docs/java/endpoints/consume_android#making-authenticated-calls
Here, they talk about 'GoogleAccountCredential.usingAudience', but nowadays, you should use GoogleAuthUtil (as far as I know, please correct me if I'm wrong).
I am trying to set up an app engine as a backend to my Android app (and in future, my iOS app).
I am using Android Studio, used the 'new module' and chose app engine with cloud messaging there.
I created a simple endpoint, and have a function there, here is some code:
public class ReviewEndpoint {
// Make sure to add this endpoint to your web.xml file if this is a web application.
private static final Logger LOG = Logger.getLogger(ReviewEndpoint.class.getName());
/**
* This method gets the <code>Review</code> object associated with the specified <code>id</code>.
* #param id The id of the object to be returned.
* #return The <code>Review</code> associated with <code>id</code>.
*/
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id) {
// Implement this function
Review r = new Review();
r.setData("test!");
As you can see, this is nicely generated by Android Studio. I implemented some stuf like creating the 'review' object and return it at the end.
On the Android side, I can do this:
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null);
ReviewEndpoint ep = b.build();
Review review = ep.getReview(1L).execute();
data = review.getData();
and yes, I get 'test!' :)
Now, I want to have this authenticated. I want to know which user wrote what, so I thought I am going to use GMail account and Facebook later.
Here I'm stuck. I am able to get a token from the user on Android:
token = GoogleAuthUtil.getToken(MainScreenActivity.this, mAccount.name, "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile");
then you are able to add this token as credential to the request:
Credential cr = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token);
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), cr);
Then in the app engine I tried to get the user info, but how?
Will it be supplied as 'bearer'? How do I get this bearer token? Should I then do API request to get the data on the server?
this does not work:
OAuthService service = OAuthServiceFactory.getOAuthService();
try {
User user = service.getCurrentUser();
can anyone give me a heads up?
So finally, today, I found out how to do it! I had questions on Stackoverflow on this before and never had an answer, but these to sites gave me the answer:
https://developers.google.com/appengine/docs/java/endpoints/auth
https://developers.google.com/appengine/docs/java/endpoints/consume_android
The first shows what needs to be done on the app engine side. The second page will tell you how to get the credentials. I was quite close. I am not sure if the adjusting of the build.gradle file mentioned in the second link is necessary. What I added to the App Engine:
#Api(name = "reviewEndpoint", version = "v1", ...<<some more stuff here >>
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
and then get the credentials:
// Initialize the scope using the client ID you got from the Console.
final String scope = "server:client_id:" + Constants.WEB_CLIENT_ID;
credential = GoogleAccountCredential.usingAudience(activity,scope);
You have to add the e-mail address of the user:
credential.setSelectedAccountName("some-mail-address#gmail.com");
you can get the e-mail address using the account picker (also example shown when you follow the link)
and next. you do a call to the endpoint, using the credential, I think Play Services will validate the user, because if I use an e-mail that is not logged in on the device, it will not work. The following code will throw an GoogleAuthIOException :
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), id_token);
ReviewEndpoint ep = b.build();
Review review;
review = ep.getReview(1L).execute();
for testing, I've put the e-mail address I get at the server side as a string in the review object, and there it gave me the e-mail address instead of the user object being null. Ow! I forgot to tell you, you need a user argument on the app engine side. Even though you do not see the 'user' argument in the 'getReview' call above, it will be added by App Engine.
So this is how my getReview looks now:
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id, User user) {
// Implement this function
Review r = new Review();
r.setData("user == " + (user == null ? "NULL " : user.toString()));
Hope this will help someone
My problem is i am not been able to receive joined chat rooms. I am using the openfire server 3.8.2 and asmack library asmack-android-16.jar. I receive item-not-found error when i call getJoinedRooms function. though i can see the user is joined in the room from the admin console. Is it the server problem or the client problem or some issue with asmack? Please tell me if someone is able to get joined chat rooms using openfire and asmack for android.
here is how i am call the function:
Iterator RoomsIterator=MultiUserChat.getJoinedRooms(MyService.getConnection(),"user#192.168.1.3");
i also tried this but it gives no response form server:
Iterator RoomsIterator=MultiUserChat.getJoinedRooms(MyService.getConnection(),"user#192.168.1.3/Smack");
Please help me with my problem
Thanks in advance.
I solved my problem by adding a packet listener after call get joined rooms function.. as i was getting an empty list but when i debug i check that the rooms was getting returned in the resultant xml stanze that was sent by the server therefore i run the getjoinedroom function of asmack and then i manually add ha packet listener like this:
public void AddPacketListener(){
PacketFilter filter = new IQTypeFilter(IQ.Type.RESULT);
MyService.getConnection().addPacketListener(new PacketListener()
{
public void processPacket(Packet paramPacket) {
if(paramPacket.getFrom().equals(MyService.getConnection().getUser())){
String xml=paramPacket.toXML();
String from[];
System.out.println(xml);
from=paramPacket.getFrom().split("/");
Pattern pattern = Pattern.compile("<item jid=\"(.*?)/>");
Matcher matcher = pattern.matcher(xml);
String parts[];
Roomlist.clear();
while (matcher.find()) {
parts=matcher.group(1).split("#");
Roomlist.add(parts[0]);
}
return;
}
}
},filter);
}
I am developing an android application..in that application there is a registration module.for that i have to implement email verification functionality.
by using the following code I am able to send email for particular email..
public void onClick(View v) {
// TODO Auto-generated method stub
try {
GMailSender sender = new GMailSender("username#gmail.com", "*******");
sender.sendMail("This is Subject",
"This is Body",
"rose.jasmine87#gmail.com",
"naresh_bammidi#yahoo.co.in"
);
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
but how to know the status, whether it has been sent or not?
I'm assuming that you're using GMailSender as defined in this post.
Internally GMailSender calls Transport.send(message) which will throw an exception if the send to the GMail server is unsuccessful, but this is being caught and suppressed, so your calling code has no way of knowing whether sending was successful. Firstly you'll need to change the GMailSender code to do something a bit more meaningful in the case of a send error.
What you must remember is that email is not delivered directly to the final recipient by your app or even the GMail server. Just because you managed to send correctly to the GMail server, does not mean that it will actually reach its intended recipient, as it could fail at any mail relay on its route. To properly detect and report on whether mail actually reaches its destination you'll need something a little more sophisticated than this.
RFC 1891 is an extension to the SMTP protocol which supports delivery status notifications, but you may need to re-architect your app to be able to use this. Essentially it works by setting flags in your outgoing message to instruct mail relays to inform you of the message status. In order for you to receive this notification, you must essentially have your own mail server which is capable of receiving emails. You will receive an email containing, for example, a delivery report once a mail relay has successfully delivered it to the recipient's mailbox.
So, to properly implement this, you'll need a mail account for your app which will receive delivery status notifications. You'll need to create an SMTPMessage object, and add a header including a "Return-Receipt-To" header, whose value is set to this mail account. You'll also need to setNotifyOptions() on your message, and then send it to the GMail server. Your app will need to check its account periodically for delivery notifications.
This is a purely email-centric approach. Without knowing your precise requirements, there are alternate mechanisms that you can use. For example, if your requirement is purely to verify that an email address exists, then you can send an email which contains a URI to a server that you control. The URI contains parameters which uniquely identify both the user, and the installation of your app. The user must click on the link, and your server component verifies the mail account. It can then use something like C2DM to inform your app that the mail account is real and valid.
Sorry if this answer is a little long, and does not offer you a simple solution, but if you want to be able to properly determine whether mail is reaching its recipient, then there is no simple answer, I'm afraid.
check below method, which will validate email from client side, simply pass mail string it will return a boolean, whether entered email is correct or not.
public boolean isEmail(String email)
{
boolean matchFound1;
boolean returnResult=true;
email=email.trim();
if(email.equalsIgnoreCase(""))
returnResult=false;
else if(!Character.isLetter(email.charAt(0)))
returnResult=false;
else
{
Pattern p1 = Pattern.compile("^\\.|^\\# |^_");
Matcher m1 = p1.matcher(email.toString());
matchFound1=m1.matches();
Pattern p = Pattern.compile("^[a-zA-z0-9._-]+[#]{1}+[a-zA-Z0-9]+[.]{1}+[a-zA-Z]{2,4}$");
// Match the given string with the pattern
Matcher m = p.matcher(email.toString());
// check whether match is found
boolean matchFound = m.matches();
StringTokenizer st = new StringTokenizer(email, ".");
String lastToken = null;
while (st.hasMoreTokens())
{
lastToken = st.nextToken();
}
if (matchFound && lastToken.length() >= 2
&& email.length() - 1 != lastToken.length() && matchFound1==false)
{
returnResult= true;
}
else returnResult= false;
}
return returnResult;
}