Find a WCF service caller's Active Directory domain username - c#

Consider a WCF service using WsHttpBinding for which only the domain users are allowed to call this service.
How can you find the Active Directory username of the caller?

Get the value of System.ServiceModel.ServiceSecurityContext.Current.WindowsIdentity.Name property.
It does not matter which binding you use as long as the security mode is different from None for the binding.
If the security mode is None then System.ServiceModel.ServiceSecurityContext.Current will be null.

You can get identity of the user by calling:
ServiceSecurityContext.Current.WindowsIdentity.Name
or
OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name

You will have to add some sort of User information to the message structure you are using to contact the service.
e.g.
public class UserInformation
{
public string User { get; set; }
public string Password { get; set; }
}
[DataContract]
public class Request
{
[DataMember]
public UserInformation User { get; set; }
[DataMember]
public MyRequest RequestBody { get; set; }
}
This way you can query active directory at your client side, populate the UserInformation object and send over the user details as part of the message structure.

Related

Duende Identity Server : How to return external provider tokens also to the Angular/WPF/MVC client along with Duende tokens

I am using Duende Identity server and I have an external authentication provider lets say google. While logging into google we get tokens from google which we can make use of calling some google API's.
I need to return the google token also to the client side(Angular/WPF/MVC etc) through Duende token endpoint.
I can see from the code that Duende token endpoint response has a Custom property, but I have no clue how or from where I can insert my values.
From Duende Source Code
internal class ResultDto
{
public string id_token { get; set; }
public string access_token { get; set; }
public int expires_in { get; set; }
public string token_type { get; set; }
public string refresh_token { get; set; }
public string scope { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Custom { get; set; }
}
I would like to see some code snippets or direction on how to add values to this Custom property by existing Duende functionality.
If you need to customize token response you can ICustomTokenResponseGenerator (It is for identity server 3, if you are using version 4 and above I am not sure but it should be ITokenResponseGenerator):
class CustomTokenResponseGenerator : ICustomTokenRequestValidator
{
public Task<TokenResponse> GenerateAsync(ValidatedTokenRequest request, TokenResponse response)
{
response.Custom.Add("custom_field", "custom data");
return Task.FromResult(response);
}
}
and then add it with factory:
factory.CustomTokenResponseGenerator = new Registration<ICustomTokenResponseGenerator, CustomTokenResponseGeneratorService>();

Best practice for performing sequential MediatR commands/queries as part of a single HTTP Request?

I am in a situation where the creation of an entity requires the creation and ID of other entities, however, I am unsure how this is best implemented using MediatR.
For example, say I have a User object...
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public ICollection<Submission> Submissions { get; set; }
}
a Submission object...
public class Submission
{
public int Id { get; set; }
public string Reference { get; set; }
public User User { get; set; }
public ICollection<QuestionsAndAnswer> QuestionAndAnswers { get; set; }
}
and a QuestionAndAnswer object.
public class QuestionAndAnswer
{
public int ID { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
public Submission { get; set; }
}
Each user can have multiple submissions and each submission has multiple questions and answers.
In this instance, the user has gone through a series of questions, provided answers, filled in the final form which provides asks for their contact details and then submitted the information to the API. At this point, I am unsure how to handle the data using MediatR, because the User must be created, with their ID returned as a result to create the submission object which in turn is required so that the questions and answers can be saved.
Should I implement a command which is called CreateUserWithSubmissionQuestionAndAnswersCommand, the handler of which somehow then calls the handlers for the three separate commands and executes them in order, and if so how?
I am just a bit lost on how to implement this scenario as a single HTTPRequest without violating CQRS. The only other way I could think of is implementing separate endpoints which perform each of these tasks individually which requires the client to make and receive three separate calls in succession (CreateUser, CreateSubmission, CreateQuestionAndAnswer)?
Anybody got any ideas?
I usually model the user interactions/user stories as MediatR requests. In most cases this means mapping an single HTTP request to a single MediatR request.
In your case this would be a single request which encapsulates the processing of the submission(s), e.g. ProcessSubmissions. This request would contain properties for the user as well as the submission(s) and the associated question/answer pairs. Then a single handler would persist the individual entities in the correct order.
For completeness, this is what this solution could look like:
public class ProcessSubmission : IRequest
{
public User User { get; set; }
public ICollection<Submission> Submissions { get; set; }
}
public class ProcessSubmissionHandler : IRequestHandler<ProcessSubmission>
{
public async Task<Unit> Handle(ProcessSubmission request, CancellationToken cancellationToken)
{
// Persist the user in the database
var userId = PersistTheUser(request.User);
foreach (var submission in request.Submissions)
{
// Persist each submission with questions and answers
}
}
}

Get user profile information via ASP.NET Membership.OpenAuth

Using Microsoft.AspNet.Membership.OpenAuth I've very quickly been able to get an app logging people in via various external provider (facebook, twitter, google, microsoft). That's great.
My question is, can I use this framework to get the users profile information easily? I'd like to get their profile picture, email address, DOB etc if the service has them.
I know there is some extra information in AuthenticationResult.ExtraData however it isn't standard and doesn't contain what I need.
Is there something I can do from here to get the information using Microsoft.AspNet.Membership.OpenAuth (or another .net lib) or will I need to use the access token in ExtraData to access the different services manually via the separate service APIs?
Thanks
There are two main issues to overcome with the authentication workflow stuff. One, as the OP rightly pointed out concerns the contents of ExtraData and the other concerns the permissions that you need to ask Facebook for. In the end I went with the DotNetOpenAuth library rather than the Microsoft one but extended it in certain places by rolling my own classes and borrowing parts of the framework where necessary.
The first thing I did was create a FacebookClient that extended the OAuth2Client from DotNetOpenAuth and allowed me to pass in a value for scope, which got past the limitation on which data you could request from Facebook. The permission I ask for are publish_stream, manage_pages, email, user_interests. They simply get appended to the service login URL and passed across to Facebook. The useful method within my implementation of OAuth2Client is GetUserData:
protected override IDictionary<string, string> GetUserData(string accessToken)
{
var token = accessToken.EscapeUriDataStringRfc3986();
FacebookGraphData graphData;
var request = WebRequest.Create(string.Format("https://graph.facebook.com/me?access_token={0}", token));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
graphData = JsonHelper.Deserialize<FacebookGraphData>(responseStream);
}
}
var userData = new Dictionary<string, string> {{"accessToken", accessToken}};
userData.AddItemIfNotEmpty("id", graphData.Id);
userData.AddItemIfNotEmpty("name", graphData.Name);
userData.AddItemIfNotEmpty("email", graphData.Email);
userData.AddItemIfNotEmpty("firstName", graphData.FirstName);
userData.AddItemIfNotEmpty("lastName", graphData.LastName);
userData.AddItemIfNotEmpty("link", graphData.Link == null ? null : graphData.Link.AbsoluteUri);
userData.AddItemIfNotEmpty("username", graphData.Username);
userData.AddItemIfNotEmpty("gender", graphData.Gender);
userData.AddItemIfNotEmpty("locale", graphData.Locale);
FacebookFriendData friendData;
request = WebRequest.Create(string.Format("https://graph.facebook.com/me/friends?access_token={0}", token));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
friendData = JsonHelper.Deserialize<FacebookFriendData>(responseStream);
}
}
if (friendData.Friends != null)
{
userData.Add("connections", friendData.Friends.Count().ToString());
}
return userData;
}
I've basically created a few data classes that are deserialized when the response comes back from Facebook. I can also make any other Graph API calls from here that I need. Serialization classes look like this:
[DataContract]
public class FacebookFriendData
{
[DataMember(Name = "data")]
public IEnumerable<Friend> Friends { get; set; }
}
[DataContract]
public class Friend
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
}
[DataContract]
public class FacebookGraphData
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "email")]
public string Email { get; set; }
[DataMember(Name = "first_name")]
public string FirstName { get; set; }
[DataMember(Name = "last_name")]
public string LastName { get; set; }
[DataMember(Name = "link")]
public Uri Link { get; set; }
[DataMember(Name = "username")]
public string Username { get; set; }
[DataMember(Name = "gender")]
public string Gender { get; set; }
[DataMember(Name = "locale")]
public string Locale { get; set; }
}
As per #radm4 I still check the provider string to decide which methods to call in certain places - still working on a more elegant solution to that one...
After looking around I can't see a way to do this only with the Microsoft.AspNet.Membership.OpenAuth stuff.
My solution has been to skip the .NET oauth stuff if the user wants to use facebook. In this case I use the facebook C# SDK to authenticate and then I can access email, birthday, photo etc.
if(provider != "facebook")
{
//do normal oauth
}
else
{
FacebookClient client = new FacebookClient();
var loginUrl = client.GetLoginUrl(new
{
client_id = ConfigurationManager.AppSettings["facebookId"],
client_secret = ConfigurationManager.AppSettings["facebookClientSecret"],
redirect_uri = redirectUrl,
response_type = "code",
scope = "email,user_birthday"
});
Response.Redirect(loginUrl.AbsoluteUri);
}
When the user returns you can then use the SDK to access this extra information.
I'm going to add this type of thing for Google too. If users want to use other services to log in they can but I'll just use asp.net oauth and they won't get as customised an experience as facebook or google until I have more time to spend on each provider.
So basically the answer is ASP.net oauth is fine for logging in and very basic information but if you need more you'll need to extend or by pass it for each provider.

Modifying the interface used for WebChannelFactory

If I have a Server/Client application that both reference the same DLL which contains interfaces used for a REST server and for the WebChannelFactory to reference the web server, what would happen to legacy clients if the Servers interface gets and update? For example say version one of an application gets pushed out with the following interface:
[ServiceContract]
public interface ISampleInterface
{
[OperationContract]
[WebInvoke(UriTemplate = "/PutDevice", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]
void PutDevice(Device device);
}
[DataContract(Namespace = "")]
public class Device
{
[DataMember]
public Guid id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
} // End of Device
This is what the REST service uses as a contract and the agent would have code similar to the following:
WebChannelFactory<ISampleInterface> client = new WebChannelFactory<IGridVisionService>(new Uri(targetHost));
ISampleInterface sampleInterface = client.CreateChannel();
sampleInterface.PutDevice(new Device() { id = Guid.Empty(), Name = "Test Device", Description = "Test Device Description" });
So the client application is already deployed to hundreds of computers, but we realize for the version we also want the client to send it's domain so we modify the device data contract to be the following:
[DataContract(Namespace = "")]
public class Device
{
[DataMember]
public Guid id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Domain { get; set; }
[DataMember]
public string Description { get; set; }
} // End of Device
It's easy to update the server, but now there are hunders of agents that do not know about the Domain. What is the proper way to deal with this situation? My only thought was to not use a DataContract but an XElement that I could manually parse. Then add login to the Server for dealing with the case of a missing Domain, but this seems sloppy. Is there a better solution that I am overlooking?
I was able to test this myself. In the case that my Client Device linking to a dll that did not know about the Domain parameter, the method call still succeeded and the Domain parameter was simply null. This is the result I was hoping for!

How can I generate a custom SOAP message

I have a site that give me this xml response on my GET request:
<ServerUnits>
<State Name="ServerName" Date="2008-04-01" >
<Users>
<User login="someUser1" Password="123456">
<User login="someUser2" Password="qwerty">
</Users>
</ServerUnits>
I want use WCF Client for work with this service.
How to discraibe Message Contract of this response for WCF Clien
It is best to create client proxies for the WCF service. It will create the data contracts for you (as mentioned by #Aliostad) so you don't have to create them manually. To do this right click on your solution and select "Add Service Reference..." from the context-menu and enter the address to your WCF service.
I think that WCF is not useful is your case.
A more simple way would be to write objects that match this xml response and just deserialize xml stream onto objects instances.
What you have posted is not a SOAP message so MessageContract is not appropriate.
I imagine what you posted is the SOAP body content so you need to do something along the line of this:
[DataContract]
public class ServerUnits
{
[DataMember]
public ServerState State { get; set; }
[DataMember]
public List<User> Users { get; set; }
}
[DataContract]
public class ServerState
{
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime Date { get; set; }
}
[DataContract]
public class User
{
[DataMember]
public string login { get; set; }
[DataMember]
public string password { get; set; }
}
UPDATE
Your message is not SOAP. But you can still use the code above if you use webHttpBinding which sends and receives POX.

Categories

Resources