Hello everybody,
Finally DataObjects.Net reached Twitter. =)
Follow us for the latest news and updates.
Follow @DataObjectsNet
Wednesday, June 22, 2011Wednesday, June 15, 2011SalesPoint sample database for MySQL
This is an addition to the previous post, for those who prefer using MySQL instead of Microsoft SQL Server. Malisa Ncube made a conversion of salespoint.sql file from DataObjects.Net 4.5 Beta 2 package to MySQL syntax and very generously published in his blog.
You will also find there some moving impressions about the SalesPoint sample running on MySQL because he is the official 'father' of MySQL driver for DataObjects.Net. Thanks, Malisa! Monday, June 13, 2011DataObjects.Net 4.5 Beta 2
Today the DataObjects.Net Team is releasing the second beta of the upcoming 4.5 version of DataObjects.Net. The beta is mostly dedicated to the security system.
All security-related classes are located in a separate assembly called Xtensive.Practices.Security. Let's explore what types to be aware of the assembly includes:
Adding the security system to your project 1. Add reference to Xtensive.Practices.Security assembly 2. Register types from Xtensive.Practices.Security in your domain. <domain connectionurl="sqlserver://./SalesPoint"upgrademode="Skip">
<types>
<add assembly="SalesPoint">
<add assembly="Xtensive.Practices.Security">
</types>
</domain>
Xtensive.Practices.Security contains the following persistent types: Principal, GenericPrincipal (both are abstract) and PrincipalRole which is used for storing role names for a principal.3. Make your own persistent type that describe a user of your application. Inherit it from Principal or GenericPrincipal classes. ![]() Principal class defines the minimum IPrincipal implementation and can be used for all kind of users, no matter whether you use login/password authorization scheme, Windows-based one or your own. GenericPrincipal class is specifically designed for login/password authorization scheme. It already contains all the required properties and methods for storing password hash, for setting password, etc. Moreover, generic principal validation service is oriented only on GenericPrincipal class and its inheritors. So, in the overwhelming majority of scenarios you should inherit from GenericPrincipal class. In the sample the login/password authorization scheme is used, so the Employee class is inherited from the GenericPrincipal one. Note that you have total control on properties of user hierarchy: you define the hierarchy inheritance scheme as well as the structure of Key fields. [HierarchyRoot]
public class Employee : GenericPrincipal
{
[Field, Key]
public int Id { get; private set; }
// Other fields
}
More about principal types: part 5. 4. Define which hashing algorithm will be used. In this version md5, sha1, sha256, sha384, sha512 hashing algorithms are provided plus plain one that allows to store passwords as is, without hashing. This might be useful for testing purposes but it is strongly recommended to use true hashing one in the real life applications. In the sample the plain one is used, here is how it can be configured: <configSections>
<section name="Xtensive.Security" type="Xtensive.Practices.Security.Configuration.ConfigurationSection, Xtensive.Practices.Security" />
</configSections>
<Xtensive.Security>
<hashingService name="plain"/>
</Xtensive.Security>
If no hashing service is set, then the system will fall back to the 'plain' one.Managing passwords and validating usersHaving the above-mentioned steps done, you are getting the ability to manage users, set their passwords and validate them. Here is how:using (var session = domain.OpenSession()) {
using (var trx = session.OpenTransaction()) {
var employee = new Employee(session);
employee.Name = "Steve Ballmer";
employee.SetPassword("developers, developers, developers, developers");
trx.Complete();
}
}
using (var session = domain.OpenSession()) {
using (var trx = session.OpenTransaction()) {
var employee = session.ValidatePrincipal("Steve Ballmer", "developers, developers, developers, developers");
Assert.IsNotNull(employee);
trx.Complete();
}
}
Defining rolesWhereas user management is the essential part of any security system, roles sometimes are used as an optional addition, thus loosing all their power. But it's you who decide whether to employ them or not. In Xtensive.Practices.Security roles are optional too.Roles are ordinary classes, not persistent ones, and so are permissions. In order to utilize the roles mechanism you inherit from base Role<T> class and declare permissions for domain model types, like here: public class EmployeeRole : Role
{
public EmployeeRole()
{
// This is base role for every employee.
// It defines read-only access to products and employees for all staff.
// All employees can see products
RegisterPermission(new Permission<Product>());
// All employees can see employees
RegisterPermission(new Permission<Employee>());
}
}
public class StockManagerRole : EmployeeRole
{
public StockManagerRole()
{
// Stock manager inherits all permissions from Employee role
// In addition, it declares write access to products
// Stock managers can see and edit products
RegisterPermission(new Permission<Product>(canWrite:true));
}
}
Here is more advanced role declaration. You can declare secure queries for persistent types and use you own permission classes as well: public class SalesRepresentativeRole : EmployeeRole
{
private static IQueryable<Order> GetOrdersQuery(ImpersonationContext context, QueryEndpoint query)
{
// Sales representative role has access to its own orders only
return query.All<Order>()
.Where(o => o.Employee == context.Principal);
}
public SalesRepresentativeRole()
{
// Sales representative inherits Employee permissions
// Sales representative can see and edit customers
RegisterPermission(new Permission<Customer>(canWrite:true));
// Sales representative can see and edit sale orders but not approve
RegisterPermission(new OrderPermission(canWrite:true, canApprove:false, GetOrdersQuery));
}
}
Important: for the ease of use give your roles parameterless constructors. If this is unacceptable, then you should provide to a framework a list of role instances. I'll describe this this later.More about roles and permissions: part 2, part 3, part 4. ImpersonationThe next question after we've successfully defined users, authentication scheme, roles and permissions is "How the hell will these parts work together?". Let's see. You already know how to validate user by the pair of name and password. If the validation is successful, you may impersonate current Session with user's account. After this is done, the security framework will provide you with all necessary infrastructure on what permission the user has, which roles he is in. using (var session = domain.OpenSession()) {
using (var trx = session.OpenTransaction()) {
var employee = session.ValidatePrincipal("Steve Ballmer", "developers, developers, developers, developers");
// Opening an impersonation context
var context = session.Impersonate(employee);
// Checking permissions
context.Permissions.Contains<Permission<Customer>>(p => p.CanRead);
context.Permissions.Contains<OrderPermission>(p => p.CanApprove);
// Closing the context
context.Undo();
trx.Complete();
}
}
Here is how permissions are used to restrict screens of the sample application: Note that currently logged in employee is in StockManager role that prohibits access to Customers and Orders. The main menu just checks whether current impersonation context contains the appropriate permission and acts accordingly by enabling or disabling controls. Probably, the most exciting and important feature of the framework is automatic application of secure filters to every query that is being executed through Session.Query endpoint. For example, if we log in with an employee who is in SalesRepresentative role, which restricts all orders to his own orders only, we will see the following picture: We logged in as a Robert King, a sales representative. He can see only his own orders as the filter is declared in SalesRepresentative role and is applied automatically. The application doesn't know about users, permissions, roles, etc. All this stuff is provided by Xtensive.Practices.Security layer. Note that Customers and Orders views are available to him, but the "Approve" button is not, because the role doesn't declare access to "Approve" action. What will happen if we log in as SalesManager? Let's see: The user also has access to Customers and Orders as SalesManager role inherits it from SalesRepresentative one. Moreover, the role doesn't have such restriction for Orders, the employee see not only his own orders but the orders of employees from his department. In addition, the button "Approve" is enabled. More on applying security filters to queries: part 6 A few notes about the impersonation context ImpersonationContext class implements IDisposable, so you can employ using pattern. The context also supports nesting. Current impersonation context instance can be accessed through Session, so you don't have to pass the reference to the context everywhere you might need it. var context = session.GetImpersonationContext(); How to build the SalesPoint sample application SQL script that builds the required "SalesPoint" database is included into the solution "Samples" and is located in the root folder of the SalesPoint project. Run the script against your database server and check that the database is successfully created. After that update the connectionUrl in app.config file according to the path of your database server. DownloadDataObjects.Net 4.5 Beta 2 can be downloaded from the website.P.S. Dear users of DataObjects.Net! This is DataObjects.Net Beta 2, so I'm asking for your feedback. Play with the sample or try creating your own one, try applying the security framework to your real projects, do anything you want with it including the most weird scenarios (I know you can), I'll be happy to receive any comment no matter good or bad from you. Any of these will definitely help to make the product better and keep our requirements for high quality product. Thank you.
Labels:
announcements,
architecture,
security
Wednesday, June 08, 2011Report about Uganda .NET Usergroup
Malisa Ncube has written a nice post about the event that took place on Friday, 27th May 2011. Malisa presented DataObjects.Net on the meeting and demonstrated how DataObjects.Net fits into Microsoft technology stack.
Don't miss the downloadable presentation. The link is located in the end of his report. Really nice one!
Labels:
community
Tuesday, June 07, 2011DataObjects.Net Entity Designer update
Talented Peter Ĺ ulek announced the major update of the Entity Designer project.
The update includes list of bug fixes along with the new important features like POCO/DTO generation support, optional DataContract and DataMember attributes generation, redesigned "Add association" dialog and much more.
Read complete announcement in Peter's blog. So, grab the bits and start playing with the tool. Any feedback is highly appreciated. The sooner the designer is tested in various scenarios, the sooner it will be released in production. So, DataObjects.Net community members, participate! Help making the tool perfect.
Labels:
announcements,
community
Saturday, June 04, 2011On security system, part 6
It seems that in the end of the previous post I was a bit wrong. One more topic left for detailed discussion. And its name is "Query conflicts resolving".
Let me explain it a bit. Say, there is a consulting firm that is managed by 2 managers. First of them, Dan, is responsible for negotiations with automobile companies, while the second one, John, works with aircraft enterprises. According to the approach that is described in the previous set of posts the security domain model would contains of two roles: AutomobileManagerRole and AircraftManagerRole, each of them would include a correspondent restrictive query. public class AutomobileManagerRole : Role
{
private static IQueryable<Customer> GetCustomers(ImpersonationContext context, QueryEndpoint query)
{
return query.All<Customer>()
.Where(c => c.IsAutomobileIndustry);
}
public AutomobileManagerRole()
{
RegisterPermission(new CustomerPermission(true, GetCustomers));
}
}
public class AircraftManagerRole : Role
{
private static IQueryable<Customer> GetCustomers(ImpersonationContext context, QueryEndpoint query)
{
return query.All<Customer>()
.Where(c => c.IsAircraftIndustry);
}
public AircraftManagerRole()
{
RegisterPermission(new CustomerPermission(true, GetCustomers));
}
}
Dan would be associated with AutomobileManagerRole and John - with AircraftManagerRole. The roles effectively avoid both of them to see customers that belong to industry other than a manager is responsible for. But imagine a situation when one of the managers, let it be Dan, left on a vacation. To continue automobile customers management process John should get access to customers of Dan for the vacation period. To achieve this, a system security administrator goes to a security administration console and temporarily adds AutomobileManagerRole to John's account. As a result, John's account starts containing 2 roles, both of them with restrictive query for customers. So, what should happen when John will execute a query for customers? How the conflict between 2 restrictive queries should be resolved? The answer is that if the first role grants access to X set of entities and the second role grants it to Y set of entities then the result of combination of these roles should be a union of X and Y, not intersect or except. Applying this approach to the situation with the managers, John will get access to the result of the following query: query.All<Customer>()
.Where(c => c.IsAutomobileIndustry)
.Union(query.All<Customer>()
.Where(c => c.IsAircraftIndustry));
This approach will be used always when impersonation context is active and user account contains more then one role with a restrictive query for a querying persistent type.
Labels:
architecture,
security
Friday, May 27, 2011On security system, part 5
After releasing DataObjects.Net 4.5 Beta 1 with Firebird & MySQL providers as well as with LINQPad provider, the team switched back to the security-related stuff.
In the previous part we discussed the roles and permissions in terms of restricting LINQ queries. This time let's focus on users, passwords and validation. First of all, according to the requirements to the security system listed in the very first post concerning this topic, we announced that it would be good if we integrate somehow with the core .NET security interfaces, like IPrincipal & IIdentity. As a result, our core IPrincipal interface inherits System.Security.IPrincipal interface and adds 2 persistent fields and 1 method: public interface IPrincipal : IEntity, System.Security.Principal.IPrincipal
{
[Field]
string Name { get; }
[Field]
[Association(PairTo = "Principal", OnOwnerRemove = OnRemoveAction.Cascade)]
PrincipalRoleSet PrincipalRoles { get; }
bool IsInRole(Role role);
}
Field 'Name' is used for storing identity information in storage. 'PrincipalRoles' is a set of roles that a principal owns. The PrincipalRole type is just a auxiliary type that help associate a Principal with its roles. A role itself is not persistent type, so we use its name as a reference. [HierarchyRoot]
[KeyGenerator(KeyGeneratorKind.None)]
public class PrincipalRole : Entity
{
[Field, Key(0)]
public IPrincipal Principal { get; private set; }
[Field(Length = 50), Key(1)]
public string Name { get; private set; }
public PrincipalRole (Session session, IPrincipal principal, string name)
: base(session, principal, name) {}
}
In order not to realize all functionality of IPrincipal interface by yourselves, there is 2 base implementations: Principal & GenericPrincipal. The first one is pure implementation of the IPrincipal interface with no additional stuff. Here it is: public abstract class Principal : Entity, IPrincipal
{
[NotNullConstraint(Mode = ConstrainMode.OnValidate)]
[Field(Length = 50, Indexed = true)]
public string Name { get; set; }
public virtual IIdentity Identity
{
get { return new GenericIdentity(Name); }
}
[Field]
public PrincipalRoleSet PrincipalRoles { get; private set; }
public bool IsInRole(string role)
{
return PrincipalRoles.Any(r => r.Name == role);
}
public bool IsInRole(Role role)
{
return PrincipalRoles.Contains(role);
}
}
The second persistent class called GenericPrincipal is designed for use in scenarios with username/password matching: public abstract class GenericPrincipal : Principal
{
[Field(Length = 50)]
public string Password { get; protected set; }
public virtual void SetPassword(string password);
}
Note that both classes neither define Key fields nor apply HierarchyRoot attribute because no prediction can be made about such properties in your domain models. However, this means that you should add your own persistent type called User or similar and inherit from Principal or GenericPrinipal types in order to use all features of the security system. No additional coding is required, just inherit one of them, define Key field(s) and apply HierarchyRoot on top and that's all.As GenericPrincipal type is intended to be used in username/password scenarios, the next question is: who will be responsible for possible encryption of passwords and how users will be validated/authenticated? The previous version of DataObjects.Net provided several password encryption algorithms you could choose from, however the possibility to implement your own one was absent. This time we are going to provide a generic interface for string encryption as well as several common implementations. Customers will have the ability to make their own implementations and plug them in. Here is the interface: public interface IEncryptionService : IDomainService
{
string Encrypt(string value);
}
It is absolutely simple and straightforward. For now there are 2 realizations: PlainEncryptionService that actually doesn't make any encryption at all and could be used for testing purposes, and Md5EncryptionService. I'll show how to configure the services later. The next part is user authentication. Keeping in mind that DataObjects.Net-based applications might operate with various types of principals, for example, Windows principal or generic one with username/password authorization scheme, we provide the following generic interface for this task: public interface IPrincipalValidationService : ISessionService
{
IPrincipal Validate(IIdentity identity, params object[] args);
IPrincipal Validate(string name, params object[] args);
}
The method that takes IIdentity as the first parameter is more generic, it might take WindowsIdentity as well as any other IIdentity descendants. The second argument is an array of values that are used for authentication, these could be passwords, tokens, tickets, you name it. The framework will provide base user validation service for username/password authentication scheme, and you'll have the ability to make your own ones. It seems that there is nothing left to describe. In the next part we'll try making our first sample with integrated security. Stay tuned.
Labels:
architecture,
security
Tuesday, May 24, 2011DataObjects.Net on Uganda .NET Usergroup
Hello All,
On Friday, 27th May 2011 Malisa Ncube will present DataObjects.Net on Uganda .NET Usergroup meeting and demonstrate how DataObjects.Net fits into Microsoft technology stack and how software engineers can accelerate project development using the application framework. It is a completely free event. If you’d like to attend, please register here.
Labels:
announcements
Wednesday, May 18, 2011DataObjects.Net 4.5 Beta 1
Today the DataObjects.Net Team is releasing the first beta of the upcoming 4.5 version of DataObjects.Net.
In this release are included both new providers: for Firebird 2.x & for MySQL 5.x as well as the LINQPad provider. Both stable versions are also updated to the latest revision. Issues resolved: - Index attribute on abstract class not in hierarchy root - No Foreign Key on field from Interface - Bug of Inheritance with non open generic - Unsufficient error message when domain build - Structure field migration The beta as well as stable versions are available in the download section of the official website. Please, report any issues concerning new providers so we could fix them before the final version is released. Thanks.
Labels:
announcements,
releases
Tuesday, May 03, 2011DataObjects.Net is updated to build 7487
Hello All,
Today, May 3, both stable versions of DataObjects.Net (v.4.3 & v.4.4) were updated to the latest revision, 7487. Bugs fixed: - Field with type of object is not initialized in DTO on query execution. Here is the detailed scenario, although simplified: public class MyEntity : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field]
public string Text { get; set; }
}
public class DTO1
{
public int Id { get; set; }
public DTO1(MyEntity entity)
{
Id = entity.Id;
}
}
public class DTO2
{
public object DTO1 { get; set; }
}
using (var session = Domain.OpenSession()) {
using (var t = session.OpenTransaction()) {
var q = session.Query.AllUpdates: - Entity.IsMaterializing flag is added to help distinguishing the case when Entity is being materialized from the case when it is being created via ordinary constructor. Usage: // Overriding Entity.OnInitialize method
protected override void OnInitialize()
{
base.OnInitialize();
if(!IsMaterializing)
// Make some new entity initialization logic
}
The updated installers as well as binaries can be downloaded from the official website: dataobjects.net. UPDATE: The detailed scenario is added to the bug fixed.
Labels:
announcements,
website
Subscribe to:
Posts (Atom)
|
SubscriptionBlog Archive
Labels
|











