Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,527
|
Comments: 51,163
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 89 words

This was how I started the day, interesting problem, and I like the solution:

DetachedCriteria getMaxScanDateForScan = DetachedCriteria.For<ScanResult>()
	.SetProjection(Projections.Max("ScanDate"))
	.Add(Property.ForName("ScanUri").EqProperty("scan.Id"));
DetachedCriteria hasResults = DetachedCriteria.For<ScanResult>()
   .SetProjection(Projections.Id())
   .Add(Property.ForName("ScanUri").EqProperty("scan.Id"));

criteria
	.CreateCriteria("Results", "result", JoinType.LeftOuterJoin)
	.SetProjection(
	Projections.ProjectionList()
		.Add(Projections.Property("scan.Id"), "Id")
		.Add(Projections.Property("scan.Uri"), "Uri")
		.Add(Projections.Property("scan.DaysNotice"), "DaysNotice")
		.Add(Projections.Property("scan.EnableScan"), "EnableScan")
		.Add(Projections.Property("result.ScanDate"), "LastScan")
		.Add(Projections.Property("result.Status"), "Status")
		.Add(Projections.Property("result.Message"), "Message")
	)
	.Add(Expression.Disjunction()
		.Add(Subqueries.PropertyEq("result.ScanDate", getMaxScanDateForScan))
		.Add(Subqueries.NotExists(hasResults))
	);

IList list = criteria
		.GetExecutableCriteria(session)
		.SetResultTransformer(new AliasToBeanResultTransformer(typeof (ScanURIReport)))
		.List();
time to read 3 min | 514 words

I just finished spending half a day implementing support for mixed mode authentication in my application. I am putting it here mostly to remind me how it is done, since it was a pretty involved process.

As usual, the requirement was that most of the users would use Windows Authentication in a single sign on fashion, and some users would get a login screen.

I am using Forms Authentication, and I want to keep is as simple as possible. After some searching, it seems that most of the advice on the web seems to include building two sites, and transfering credentials between the sites.

Perhaps the best places to look for it is this image, that explains how Forms Authentication works, and these two posts from Craig Andera #1, #2. After reading those, I had a much better picture of what I needed to do.

This requires several steps that are supposed to be self coordinated in order for it to work:

  • Setup IIS for Anonmous + Integrated security.
  • In the web.config, specify forms authentication.
  • In the Login Controller, you need to check whatever the user is a candidate or windows authentication. In my case, it is decided according to IP ranges, but your case may be different.
  • If the user can do windows authentication, you need to send back a 401 status code.
  • Here is where it get a bit hairy. You can't do it from the login controller, because the FormsAuthentication Module will intercept that and turn it into a redirect to the login page.
  • You need to create a http module and register it last in the HttpModule sections, and there you can specify the 401 status code safely. I used the HttpContext.Items to transfer that request.
  • After the request has returned, if Windows Authenticaton has been successful, you can access the user name in the ServerVariables["LOGON_USER"].
  • Create a Form Authentication cookie as usual, and carry on with your life.

The main issue here, as far as I am concerned was to make sure that I will do it in a way that is maintainable, there are several disparate actions that are taking place that are all needed to make it work.

It took a while before I could get to grip with what was going on the wire, so here is the code for this:

private void HandleInternalUsersAndSingleSignOn()
{
	//semi-internal users and the like
	if(Context.ClientIpIsIn(Settings.Default.ExcludeFromWindowsAuthetication))
		return;
	string logonUser = Context.GetLogonUser();
	if(string.IsNullOrEmpty(logonUser))
	{
		//Internal installation and an empty user means
		//that we have not yet auttenticated, we register a request
		//to send a 401 (Unauthorized) to the client, so it will provide
		//us with their windows credentials.
		//we have to register a request for 401, which will be handled by the
		//Add401StatusCodeHttpModule on the EndRequest because we are also using
		//FormsAuthentication, and we need to bypass the FormAuthentication interception
		//of 401 status code.
		Context.SetContextVaraible(Constants.Request401StatusCode, true);
		Context.EndResponse();
	}
	// will redirect to destination page if successful
	LoginAuthenticatedUser(logonUser);
}
time to read 2 min | 248 words

Another semi-post morten talk that we had today had to do about complexity. A co-worker has just found my windsor.boo file, and commented on the complexity that it invovles. We had a discussion about this. I aggreed with her that this is indeed complex, but, in over eight months of the  project, it was the irst time that someone other than me had to deal with it, and for the rest of the team it Just Worked.

Side note: one of the things that I am going to make sure for the next project is make sure that the entire team has at least a rudimetry understanding of all the important infrastructure pieces.

It got us to a discussion of whatever we can reduce the complexity. Considering what we need to handle in this project, we both agreed that we could not significantly reduce the complexity of the system and that the alternative were either going with a localized complexity zone or spreading it around the entire code base if we removed this functionality.

We couldn't reduce complexity, we could only move it around. By certralizing it in a single place we increased the local complexity of a single part of the application (not the complexity of the code, but the cmpliexity in understanding what is going there, IoC & DI ). But trade off is that we made the rest of the code of the system much easier to work with and understand.

What do you think?

time to read 1 min | 126 words

I mentioned that we are on the closing of a project, and we have already started to work on side projects and preparing for the next one.

In the current project, I have setup a lot of the inrasturcture myself, and then the team started to work on it. I had a discussion with a co worker today about it, she had a lot of frustration because she couldn't work on the side project the way she was used to in this project.

We setup most of everything that she needed, but one thing that she said stuck with me:

I don't know how to develop on .NET, I know how to develop on .OREN

I found it funny, but we still scheduled training sessions...

time to read 1 min | 69 words

I was asked to add a few fields to a report that we are showing, I had to touch the following parts of the system:

  • Database table
  • SSIS
  • Entity
  • Report page
  • Export to excel

I spent about 20% of the time in SSIS and another 70% in trying to fit the new fields into the current page without causing horizional scroll bar.

Pretty good balance, I would say.

time to read 1 min | 134 words

Well, I am not going to give the implementation here, but here are some notes for the implementation. What you basically need is actually quite simple.

  • Start with a partial query, as shown here.
  • Instead of returning the object, return a proxy to the object, that is aware of which properties were loaded.
  • When a property is accessed that is not in the loaded properties list, do the following:
    • Load the real object using NHibernate.
    • Copy the existing values from the current object to the newly loaded one. (Preserving state)
    • Redirect all calls to the newly loaded object.

The whole thing is quite simple, once you think about it from the right angle. Then again, here talks the guy who spent two hours debugging why calling the wrong machine would fail.

time to read 2 min | 310 words

Aaron still wants partial object queries, so I set up to build them using NHibernate. Here is the implementation, notice that this query will result in a list of Blog instances, but the select will only include their titles & subtitles.

using (ISession session = sessionFactory.OpenSession())
{
	TupleToPropertyResultTransformer transformer = 
		new TupleToPropertyResultTransformer(typeof(Blog),"Title", "Subtitle");
	IList list = session.CreateQuery("select b.Title, b.Subtitle from Blog b")
		.SetResultTransformer(transformer)
		.List();
	foreach (Blog b in list)
	{
		System.Console.WriteLine("Blog: {0} - {1}", b.Title, b.Subtitle);
	}
}

But where does TupleToPropertyResultTransformer comes from, well, that is where the magic comes in, here is my implementation for it:

public class TupleToPropertyResultTransformer : IResultTransformer
{
	private Type result;
	private PropertyInfo[] properties;

	public TupleToPropertyResultTransformer(Type result, params string[] names)
	{
		this.result = result;
		List<PropertyInfo> props = new List<PropertyInfo>();
		foreach (string name in names)
		{
			props.Add(result.GetProperty(name));	
		}
		properties = props.ToArray();
	}

	public object TransformTuple(object[] tuple, string[] aliases)
	{
		object instance = Activator.CreateInstance(result);
		for (int i = 0; i < tuple.Length; i++)
		{
			properties[i].SetValue(instance, tuple[i], null);
		}
		return instance;
	}

	public IList TransformList(IList collection)
	{
		return collection;
	}
}

This isn't the most optimized version that you can think of, but it does the job.

I want to make it clear, however, that I feel that doing stuff like this is not something that I would consider to be a best practice. Quite the opposite, frankly. What we have here is an object in a state that it was never intended to be, with only part of its fields filled, and certainly not based on any logic. I would much rather see a DTO class take its place, because that has a clear responsibility in the application, reusing your entities as dumb data container is not something that I would recommend.

time to read 1 min | 180 words

image

Well, it looks like I have once again managed to put myself in a tricky spot. I have the following scenario:

  • Domains: A1 & A2 - no trust or any association between the two.
  • A user access a Website on A1, using windows authentication, which makes a web service call to a machine on domain A2 (anonymous security, at the moment).
  • As a result of the web service call, the machine on A2 needs to make another web service call to A1, and it needs to do it with windows authentication, with the credentials of the original user.

Now, I have control on the machine in A1 (.Net 1.1 ASMX WebServices) and I can do whatever I want to the machine in A2 (WCF). No trust between the domains, as I said, so I don't think that I can make Windows Authentication works between the two. Frankly, I don't care about authenticating users, I just need their credentials when I am going back to the machine in A1.

Any suggestions?

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB Cloud (2):
    26 Nov 2024 - Auto scaling
  2. Challenge (75):
    01 Jul 2024 - Efficient snapshotable state
  3. Recording (14):
    19 Jun 2024 - Building a Database Engine in C# & .NET
  4. re (33):
    28 May 2024 - Secure Drop protocol
  5. Meta Blog (2):
    23 Jan 2024 - I'm a JS Developer now
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}