Inconsistent results when listing groups an external account belongs to - asp.net

Our Google domain has groups (synced copies of our Active Directory email listservs/distribution groups) that have a lot of external accounts (currently kept as contacts in Active Directory).
As part of an intranet site I'm building I'm trying to be able to do mass search and replace of individual contact email address when for example a school district changes its domain name. One of the visual/verification steps I'm working on is to list the Google group membership of any selected external account, but I'm getting mixed results. For some accounts it seems to list the groups properly, and for others it doesn't seem to pull any. I have verified the external account's group membership in both Active Directory and in Google Admin group management, but when I query Google via code I don't get valid results every time... What am I missing? Code below.
-- in Global.asax
public static List<string> GOOGLE_GetListOfUsersGroups(string useremail)
{
List<string> groupList = new List<string>();
try
{
///stripped out credential/service stuff...
var groups = service.Groups.List();
groups.UserKey = useremail;
Groups gs = groups.Execute();
if (gs != null)
{
foreach (Google.Apis.Admin.Directory.directory_v1.Data.Group g in gs.GroupsValue)
groupList.Add(g.Email);
}
}
catch (Exception ex)
{
SendERROREmail("GLOBAL<HR>GOOGLE_GetListOfUsersGroups()<HR>useremail:" + useremail + "<HR>" + ex.ToString());
}
return groupList;
}
and the consuming function:
--- in Page.aspx
protected void ddlADExternalContacts_SelectedIndexChanged(object sender, EventArgs e)
{
lbContactsGoogleGroups.Items.Clear();
if (ddlADExternalContacts.SelectedIndex > 0)
{
//show what google has for same group
List<string> memberList = Global.GOOGLE_GetListOfUsersGroups(ddlADExternalContacts.SelectedValue);
if (memberList != null)
{
foreach (string s in memberList)
lbContactsGoogleGroups.Items.Add(new ListItem(s, s));
}
}
}
Also, does anyone have a good example how to handle this in Google's 'preferred' JSON format rather then the API route?
UPDATE: Ok, its not my code, its something with the group/Google. When I use the 'try it' functionality on the sdk admin site I get the same results for groups that work (in my code and their site) and no results from the same groups that should be showing results...
{
"kind": "admin#directory#groups",
"etag": "\"HKdfSgTnCxrWl3RtRnlZSCPY3NjdWJxz53nrhwSz7ob4/oMWMqbsluP5m2PCo8Y7WmWeHGP4\""
}
Not that that helps me any, as there's no error or anything, just the 'no groups' result as if it can't find the external account...
UPDATE2: Ok, based on what I'm seeing after some testing, I have a sneaky suspicion that Google is doing some validation of emails before checking for group membership and reporting anything. I.E. if the email being searched for is no longer valid (client's server doesn't responds that the account is reachable/enabled/exists...), it won't bother going any further... will try it out with a few more email addresses that I know should be invalid and update....later.

It looks like what you are experiencing might be a bug.
This has been reported on Google Issue Tracker here.
What you can do in this situation is to star the issue above and eventually add a comment saying that you are affected by it.

Related

How to capture custom parameters in firebase deep link in Unity?

everyone!
I'm working for the first time ever in a Unity game project using Firebase.
We configure our deep link in Firebase console to open our game in a specific mode when te deep link was sent.
That part works well. But we have a big issue:
We need to get a value form a custom parameter in the URL, because our server generates a random username for our game to make a Leader Board sandbox everytime the deep link was sent.
So we configure our deep link in Firebase console like this:
https://exemple.page.link/gamemode?username=123
But, in this case, the username will always be 123. However, the server will always send the link with a random user, for example:
https://exemple.page.link/gamemode?username=8b9d-1c6b-c52a3-b0d7
If we leave the username parameter blank, even if the server sent the random username, we receive nothing in our link in Unity, just:
https://exemple.page.link/gamemode?username
If I manage to get the link in a browser in my Android device, I get the random username properly. But when the game opens, this value was lost!
To receive the dynamic link, we just use the void OnDynamicLink(object sender, EventArgs args) in our Firebase Manager script in Unity.
So, my question is:
There is a way to receive the username parameter with a dynamic value? If the answer is 'yes', there's a method to get that custom value? Or I just missed up something in the firebase configuration or even the deep link in Firebase console?
Thanks in advance!
From Receive Dynamic Links with Unity you need to cast to ReceivedDynamicLinkEventArgs
void OnDynamicLink(object sender, EventArgs args)
{
var dynamicLinkEventArgs = args as ReceivedDynamicLinkEventArgs;
Debug.Log($"Received dynamic link {dynamicLinkEventArgs.ReceivedDynamicLink.Url.OriginalString}");
}
and then if there is only this one parameter anyway you could probably simply do e.g.
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
var username = query.Split('=')[1];
or if there can be more parameter
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
// first Split into the individual patamters
var patamters = query.Split('&');
string username = null;
foreach(var parameter in parameters)
{
// Then split into key and value
var keyValue = parameter.Split('=');
if(keyValue[0] == "username")
{
username = keyValue[1];
break;
}
}
or if you happen to be a fan of Linq (not sure if this is the most elegant though)
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
var username = query.Split('&').Select(parameter => parameter.Split('=').Where(keyValue => keyValue[0] == "username").Select(keyValue => keyValue[1]).FirstOrDefault();

How do we get the rights of a user in Sailpoint?

I'm trying to write a policy violation in Sailpoint. But I don't know how to get the rights of the user who is asking a new right. I've tried this:
List links1 = null;
IdentityService service = new IdentityService(context);
Application app1 = context.getObjectByName(Application.class, "Autres");
try {
links1 = service.getLinks(identity, app1);
} catch (Exception e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
List DUList1 = new ArrayList();
if(links1.size() != 0){
Object DUObj = links1.get(0).getAttribute("DU");
if(DUObj != null){
if (DUObj instanceof String)
DUList1.add((String) DUObj);
else
DUList1.addAll((List) DUObj);
}
}
It was supposed to return the list of the rights that the user has and the rights that he is asking. But it doesn't work.
"Links" in IIQ are accounts, which are entities that you get from IIQ Applications.
IIQ works with 2 types of "rights", which are entitlements and roles.
Entitlements are usually aggregated from IIQ Applications as "groups", while Roles are manually defined as pure IIQ entities. You may think of Roles as groups of entitlements (roughly speaking).
So in order to check what "rights" an IIQ identity has, you must check entitlements and roles.
Since you're working on a policy, I am assuming you're trying something for the access request. In this case, you can consider that roles will be translated into a set of entitlements, so all we have to check are, in the end of the day, entitlements.
I suppose your application "Autres" is aggregating both accounts and entitlements, right? So in your application schema, there is at least 1 account attribute that is marked as "entitlement". Let's say you have something like this
Account schema
login (correlates to your identity, identifies your account uniquely)
fullname
groupsXYZ (correlates to your entitlements)
Then your rule will get the entitlements using something like this
Application app = context.getObjectByName(Application.class, "Autres");
Link account = identity.getLink(app);
Object groups = account.getAttribute("groupsXYZ");
if (groups == null){
...
}else if (groups instanceof List){
...
}else if (groups instanceof String){
...
}
Now, notice that groups can be a List or a String. It depends if your account has one or more entitlements associated to it. Because of that, you need to check the type first (I really don't know why IIQ does not use List always, probably because the way they map their XMLs internally), but you must be careful with it and provide the appropriate typecast.
So in the case you're showing, does "DU" maps to an application account attribute which represents the entitlement? You can debug and print all the attributes for example in order to see what's associated to your account (link).
Now, if we're not talking about entitlements, but about IIQ Roles, then we're talking about something like this
Bundle someRole = context.getObjectByName(Bundle.class,"My IIQ Role ABC");
boolean hasRole = identity.hasRole(someRole);

Exchange Web Services find item by unique id

I just started using Microsoft Exchange Web Services for the first time. Want I want to be able to do is the following:
Create Meeting
Update Meeting
Cancel/Delete Meeting
These meetings are created in an ASP.NET MVC application and saved into a SQL Server database. I simply wish to integrate this with the on site Exchange Server. So far, I'm able to created my meeting with the following code:
public static Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
var tcs = new TaskCompletionSource<string>();
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = CredentialCache.DefaultNetworkCredentials;
//service.UseDefaultCredentials = true;
// I suspect the Service URL needs to be set from the user email address because this is then used to set the organiser
// of the appointment constructed below. The Organizer is a read-only field that cannot be manually set. (security measure)
service.AutodiscoverUrl(from);
//service.Url = new Uri(WebConfigurationManager.AppSettings["ExchangeServer"]);
Appointment meeting = new Appointment(service);
meeting.Subject = subject;
meeting.Body = "<span style=\"font-family:'Century Gothic'\" >" + body + "</span><br/><br/><br/>";
meeting.Body.BodyType = BodyType.HTML;
meeting.Start = begin;
meeting.End = end;
meeting.Location = location;
meeting.ReminderMinutesBeforeStart = 60;
foreach (string attendee in to)
{
meeting.RequiredAttendees.Add(attendee);
}
meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);
tcs.TrySetResult(meeting.Id.UniqueId);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
return tcs.Task;
}
This successfully creates my meeting, places it into the user's calendar in outlook and sends a meeting request to all attendees. I noticed the following exception when attempting to call meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy); twice:
This operation can't be performed because this service object already has an ID. To update this service object, use the Update() method instead.
I thought: Great, it saves the item in exchange with a unique id. I'll save this ID in my application's database and use it later to edit/cancel the meeting. That is why I return the id: tcs.TrySetResult(meeting.Id.UniqueId);
This is saved nicely into my application's database:
Now, I am attempting to do the next part where I update the meeting, but I cannot find a way to search for the item based on the unique identifier that I'm saving. An example I found on code.msdn uses the service.FindItems() method with a query that searches the subject:
string querystring = "Subject:Lunch";
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, querystring, view);
I don't like this. There could be a chance that the user created a meeting outside of my application that coincidentally has the same subject, and here come's my application and cancel's it. I tried to determine wether it's possible to use the unique id in the query string, but this does not seem possible.
I did notice on the above query string page that the last property you can search on is (property is not specified) that searches in "all word phase properties.". I tried thus simply putting the id into the query, but this returns no results:
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, "AAMkADJhZDQzZWFmLWYxYTktNGI1Yi1iZTA5LWVmOTE3MmJiMGIxZgBGAAAAAAAqhOzrXRdvRoA6yPu9S/XnBwDXvBDBMebkTqUWix3HxZrnAAAA2LKLAAB5iS34oLxkSJIUht/+h9J1AAFlEVLAAAA=", view);
Use the Appointment.Bind static function, providing a service object and the ItemId saved in your database. Be aware with meeting workflow (invite, accept, reject) can re-create a meeting on the same calendar with a new ItemId. But if you are just looking at the meeting you make on your own calendar, you should be OK.

Restrict access to all asp.net pages

I am mainlining one asp.net Project, this project is configured in IIS. The website is open for everyone, when i review the code in asp.net page, its checking window login "enterprise id" and allowing all users to view the all the aspx pages.
Now, my management team requested us to restrict those who are under junior level employees.(Junior engg, Developer, software engg).
I have written the query, passing enterprise id and validate grade, if its junior level , returning "0" values,else returning "1" values.
My questions is, I do not want go and edit each page and check this query and restrict each page.
can you please suggest , how can i implement simplest and best way to restric the users.
Thanks,
--------------------------------------- Update on 09/24/2015
Index.aspx
protected void Page_Load(object sender, EventArgs e)
{
string UserStatus = UtilFunctions.ValidateUser();
Response.Write(UserStatus);
if (UserStatus == "0")
{
Response.Write("<div><font color=red><h1>You are not authorized to view this page</h1></font></div>");
Response.End();
}
}
Utilifunctions.cs
public static String ValidateUser()
{
string CurrentUser = getLoggedOnUser();
using (System.Data.SqlClient.SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDB"].ConnectionString))
{
using (SqlCommand myCommand = myConnection.CreateCommand())
{
myConnection.Open();//Opens the Connection
myCommand.CommandText = "Select Permission From Temp_Validate Where EnterpriseId='" + CurrentUser + "'";
SqlDataReader IDReader = myCommand.ExecuteReader(); //Gets the ID
IDReader.Read();
string UserStatus = IDReader["Permission"].ToString();
IDReader.Close();
return UserStatus;
}
}
I implemented the above functionalite in my index.aspx page, if the userstatus equal to "0" , it will display the "You are not authrized to view this message" and it will end.
I have around 30 aspx page,its currently running in Production. I do not want go include the same code (index.aspx) in every page load to stop the user validation.
could you please suggest how can i implement without editing all pages.
Updated on 09/28 : Utilifunction.cs
public static String getLoggedOnUser()
{
String user = HttpContext.Current.User.Identity.Name.Substring(HttpContext.Current.User.Identity.Name.IndexOf("\\") + 1);
if (user == "") user = "anonymous";
string UserStatus = IsValidUser(user);
if (UserStatus == "0")
{
HttpContext.Current.Response.Redirect("PSF_Error.aspx", true);
}
return user;
}
public static String IsValidUser(string currentUser)
{
using (System.Data.SqlClient.SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
{
using (SqlCommand myCommand = myConnection.CreateCommand())
{
//Gets email of the creator of current user
myConnection.Open();//Opens the Connection
myCommand.CommandText = "Select Permission From Temp_Validate Where EnterpriseId='" + currentUser + "'";
SqlDataReader IDReader = myCommand.ExecuteReader(); //Gets the ID
IDReader.Read();
string UserStatus = IDReader["Permission"].ToString();
IDReader.Close();
return UserStatus;
}
}
}
Index.aspx
Page_load
{
string CurrentUser = UtilFunctions.getLoggedOnUser();
}
You have a few options, here:
1) Set up role-based access with Owin or AspNet.Identity. This is probably your best option, but I couldn't find a good tutorial for you. Those packages are well-documented, however, and I'm sure you can figure them out with some effort.
2) Build a Roles table, and customize access yourself. The best example I found was here: http://www.codeproject.com/Articles/875547/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NET
3) Redirect unauthorized users without the use of roles. So something like:
public ActionResult SecurePage(User u)
{
if(u.level == "junior"){
return RedirectToAction("CustomErrorPage");
} else {
return View();
}
}
I'm not sure that that option is terribly secure, but it should work.
Hope that helps!
after setting up roles you can use a web.config file in every directory specifying authorization and/or use the 'location' element in the web.config file.
First off, sorry about the confusing code. I've been using MVC, and you've clearly posted your code behind.
I don't think that you can achieve what you are trying to do, without adding your code to each page, or learning about roles. You could reduce some code duplication in a number of clever ways, but I can't think of anything that doesn't seem like a total hack.
If you want to, say, put all of your secure pages in the same directory, and restrict low-level access to that directory, you are going to have to filter by specific users or, if you can implement them, roles. As I understand it, the deny and allow nodes in your web.config file are setting server side (so IIS, probably) authorization rules, so the keywords and rules you can use are limited. Check this page out, for some basics:
http://weblogs.asp.net/gurusarkar/setting-authorization-rules-for-a-particular-page-or-folder-in-web-config
While it is likely POSSIBLE to build a rule based on values in your DB, doing so would probably be far more work than it would be worth.
Sorry that I can't offer a more satisfactory answer, but I would recommend: 1) Get to work, and add a check to the code behind for each page, or 2) (and I highly suggest this option) close this question, and post another, about implementing roles in .net, and assigning roles to users, in code. If, say, you can use your login page to assign every junior-level user the custom role of Junior, and place all of your secure pages in a directory named SecurePages you could add the following code to your web.config, and achieve exactly what you are trying to do:
<location path="SecurePages">
<system.web>
<authorization>
<deny roles="Junior">
<deny users="*">
</authorization></system.web></location>
Good luck!

Facebook Connect and ASP.NET

I'm at step 8 of the authentication overview found here: http://wiki.developers.facebook.com/index.php/How_Connect_Authentication_Works
In particular, the user has logged into facebook via Facebook Connect and their web session has been created. How do I use the facebook developer toolkit v2.0 (from clarity) to retrieve information about the user. For example, I'd like to get the user's first name and last name.
Examples in the documentation are geared towards facebook applications, which this is not.
Update
Facebook recently released the Graph API. Unless you are maintaining an application that is using Facebook Connect, you should check out the latest API: http://developers.facebook.com/docs/
I had a lot of trouble figuring out how to make server side calls once a user logged in with Facebook Connect. The key is that the Facebook Connect javascript sets cookies on the client once there's a successful login. You use the values of these cookies to perform API calls on the server.
The confusing part was looking at the PHP sample they released. Their server side API automatically takes care of reading these cookie values and setting up an API object that's ready to make requests on behalf of the logged in user.
Here's an example using the Facebook Toolkit on the server after the user has logged in with Facebook Connect.
Server code:
API api = new API();
api.ApplicationKey = Utility.ApiKey();
api.SessionKey = Utility.SessionKey();
api.Secret = Utility.SecretKey();
api.uid = Utility.GetUserID();
facebook.Schema.user user = api.users.getInfo();
string fullName = user.first_name + " " + user.last_name;
foreach (facebook.Schema.user friend in api.friends.getUserObjects())
{
// do something with the friend
}
Utility.cs
public static class Utility
{
public static string ApiKey()
{
return ConfigurationManager.AppSettings["Facebook.API_Key"];
}
public static string SecretKey()
{
return ConfigurationManager.AppSettings["Facebook.Secret_Key"];
}
public static string SessionKey()
{
return GetFacebookCookie("session_key");
}
public static int GetUserID()
{
return int.Parse(GetFacebookCookie("user"));
}
private static string GetFacebookCookie(string name)
{
if (HttpContext.Current == null)
throw new ApplicationException("HttpContext cannot be null.");
string fullName = ApiKey() + "_" + name;
if (HttpContext.Current.Request.Cookies[fullName] == null)
throw new ApplicationException("Could not find facebook cookie named " + fullName);
return HttpContext.Current.Request.Cookies[fullName].Value;
}
}
I followed up on this concept and wrote a full fledged article that solves this problem in ASP.NET. Please see the following.
How to Retrieve User Data from Facebook Connect in ASP.NET - Devtacular
Thanks to Calebt for a good start on that helper class.
Enjoy.
Facebook Connect actually isn't too difficult, there's just a lack of documentation.
Put the necessary javascript from here: http://tinyurl.com/5527og
Validate the cookies match the signature provided by facebook to prevent hacking, see: http://tinyurl.com/57ry3s for an explanation on how to get started
Create an api object (Facebook.API.FacebookAPI)
On the api object, set the application key and secret Facebook provides you when you create your app.
Set api.SessionKey and api.UserId from the cookies created for you from facebook connect.
Once that is done, you can start making calls to facebook:
Facebook.Entity.User user = api.GetUserInfo(); //will get you started with the authenticated person
This is missing from the answers listed so far:
After login is successful, Facebook recommends that you validate the cookies are in fact legit and placed on the client machine by them.
Here is two methods that can be used together to solve this. You might want to add the IsValidFacebookSignature method to calebt's Utility class. Notice I have changed his GetFacebookCookie method slightly as well.
private bool IsValidFacebookSignature()
{
//keys must remain in alphabetical order
string[] keyArray = { "expires", "session_key", "ss", "user" };
string signature = "";
foreach (string key in keyArray)
signature += string.Format("{0}={1}", key, GetFacebookCookie(key));
signature += SecretKey; //your secret key issued by FB
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(signature.Trim()));
StringBuilder sb = new StringBuilder();
foreach (byte hashByte in hash)
sb.Append(hashByte.ToString("x2", CultureInfo.InvariantCulture));
return (GetFacebookCookie("") == sb.ToString());
}
private string GetFacebookCookie(string cookieName)
{
//APIKey issued by FB
string fullCookie = string.IsNullOrEmpty(cookieName) ? ApiKey : ApiKey + "_" + cookieName;
return Request.Cookies[fullCookie].Value;
}
The SecretKey and ApiKey are values provided to you by Facebook. In this case these values need to be set, preferably coming from the .config file.
I followed up from Bill's great article, and made this little component. It takes care of identifying and validating the user from the Facebook Connect cookies.
Facebook Connect Authentication for ASP.NET
I hope that helps somebody!
Cheers,
Adam
You may also use SocialAuth.NET
It provides authentication, profiles and contacts with facebook, google, MSN and Yahoo with little development effort.
My two cents: a very simple project utilizing the "login with Facebook" feature - facebooklogin.codeplex.com
Not a library, but shows how it all works.

Resources