.NET Framework Developer Center > .NET Development Forums > Windows Communication Foundation > [WCF-RC1] Adding claims in UserNamePasswordValidator
Ask a questionAsk a question
 

Answer[WCF-RC1] Adding claims in UserNamePasswordValidator

  • Thursday, October 19, 2006 5:31 PMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    OK, another dumb *** question (folks, I am _trying_ to research these things first before bothering you, and I'm starting to feel like a child who can't do his homework!)

    My STS is based on the Federation example in the RC1 release, and it uses a custom UserNamePasswordValidator to validate the client credentials.  In the Validate method, I look up the user in the DB, validate the password etc and return true.

    Then, within the GetIssuedClaims override that "Issue" calls, I need to create the claims that will be added to the SamlToken.  However, the values of the claims that I want to add are stored in the DB in the row that I just looked up in the Validate method, and I really don't see why I would need to look them up again.

    How can I get Validate to add data to a context (or whatever) that GetIssuedClaims can get access to to create the claims?

    Pete


Answers

  • Friday, October 20, 2006 11:34 AMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Thanks for feedback guys.. 

    So it's seems that if I want to avoid multiple lookups, that a Validator is not the way to go - I should be using an IAuthorisationPolicy.  Perhaps this is OK.. the result of the call to Issue is either an Authenticated or Unauthenticated token as opposed to an Authenticated token or AccessDenied exception.

    However I'm still confused..  My STS is creating the SamlToken within the Issue operation of the STS (which seems to be the pattern I've seen in all the STS implementations that I have looked at).. But this call obviously comes after both the Validator.validate and the AuthorisationPolicy.Evaluate. - how do I get from what you are suggesting to the GetIssuedClaims method that Issue calls?

    Perhaps I'm missing something in both your implementations as they don't seem to address my problem?

    - Is the STS implementation in the Federation example the pattern that should be used?

    - There seems to be so many choices around the security story (validators, authenticators, policies etc), they must have been designed with particular use cases in mind - my use case would seem to be standard: an STS authenticating against a DB - I find it hard to believe that the solution is so disjointed or convoluted?

    Anyway, thanks so far.. heres hoping the penny drops with me soon...

    Pete



  • Wednesday, August 08, 2007 2:00 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

     Taavi Koosaar wrote:
    Do the policies that are specified in the configuration also get applied after i have coded in to add the policy in the authenticator.

     

    I'm not clear on which policies you're referring to.  If you're asking about external authorization policies or a SerivceAuthorizationManager the answer is yes.

     

     Taavi Koosaar wrote:
    However, the ServiceCredentialsElement class is sealed, so i cannot inherit from it.

     

    This is fixed in Orcas.

     

     Taavi Koosaar wrote:
    Is there a way to add our own Identity, so that the evaluation context would have our custom one?

     

    Set the Identities property on the auth policy returned from the authenticator.  A quick search will turn up the many threads discussing this.

All Replies

  • Thursday, October 19, 2006 7:12 PMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    You can utilize an Authorization Policy that captures the system issued identity claims which are the result of your UserNamePasswordValidator being called, then install the appropriate additional claims based on those values [or at least that's how we did it].

    We utilized this model to install things like userID, roles, etc into the outgoing claims that are part of the STS generated token.  The primary problem is that that UsernamePasswordValidator is called prior to any of the context stuff being setup [but you may be able to hook some context in prior to that which could store interim values], so there's no way to add claims there from what I can see.

     

  • Thursday, October 19, 2006 8:30 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    There's indeed no way to expose claims from a UserNamePasswordValidator directly.  You can expose claims by derving from UserNameSecurityTokenAuthenticator and plugging in your derived class.  The code below shows how to do this, using the password as an example claim.  You'll want to change ValidateUserNamePasswordCore() to talk to your validator and UserNameAuthorizationPolicy to hold the claims.

     

    Disclaimer: this code is not secure since no validity check is done on the username/password pair.

     

        class UserNameAuthorizationPolicy : IAuthorizationPolicy

        {

            DefaultClaimSet claims;

     

            public UserNameAuthorizationPolicy(string userName, string password)

            {

                this.claims = new DefaultClaimSet(Claim.CreateNameClaim(userName), new Claim("Password", password, Rights.PossessProperty));

            }

     

            public bool Evaluate(EvaluationContext evaluationContext, ref object state)

            {

                evaluationContext.AddClaimSet(this, this.claims);

                return true;

            }

     

            public string Id { get { return typeof(UserNameAuthorizationPolicy).FullName; } }

            public ClaimSet Issuer { get { return ClaimSet.System; } }

        }

     

        class UserNamePasswordAuthenticator : UserNameSecurityTokenAuthenticator

        {

            protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)

            {

                List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);

                policies.Add(new UserNameAuthorizationPolicy(userName, password));

                return policies.AsReadOnly();

            }

        }

     

        class UserNamePasswordServiceCredentials : ServiceCredentials

        {

            public UserNamePasswordServiceCredentials()

            {

                // no op

            }

     

            public UserNamePasswordServiceCredentials(UserNamePasswordServiceCredentials other)

                : base(other)

            {

                // no op

            }

     

            protected override ServiceCredentials CloneCore()

            {

                return new UserNamePasswordServiceCredentials(this);

            }

     

            public override SecurityTokenManager CreateSecurityTokenManager()

            {

                return new UserNamePasswordSecurityTokenManager(this);

            }

        }

     

        class UserNamePasswordSecurityTokenManager : ServiceCredentialsSecurityTokenManager

        {

            public UserNamePasswordSecurityTokenManager(ServiceCredentials parent)

                : base(parent)

            {

                // no op

            }

     

            public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)

            {

                if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)

                {

                    outOfBandTokenResolver = null;

                    return new UserNamePasswordAuthenticator();

                }

                return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);

            }

        }

     

                string hostname = Dns.GetHostEntry(String.Empty).HostName;

                CustomBinding binding = new CustomBinding(SecurityBindingElement.CreateSecureConversationBindingElement(SecurityBindingElement.CreateUserNameForSslBindingElement()), new HttpTransportBindingElement());

                ServiceHost serviceHost = new ServiceHost(typeof(UserNameService), new Uri(String.Format("http://{0}:8000/UserName", hostname)));

                ServiceEndpoint serviceEndpoint = serviceHost.AddServiceEndpoint(typeof(IUserName), binding, "Endpoint");

                serviceHost.Description.Behaviors.Add(new UserNamePasswordServiceCredentials());

                serviceHost.Credentials.ServiceCertificate.Certificate = CertFinder.FindMachineCertificate();

                serviceHost.Open();
  • Thursday, October 19, 2006 8:56 PMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Todd,

      Is the above really the recommended way of approaching this, the variant that I'm using is much simpler than that:

        class CustomUsernameValidator : UserNamePasswordValidator
        {
            public override void Validate(string userName, string password)
            {
                if (userName == "testuser")
                {
                    return;
                }

                throw new FaultException(
      new FaultReason("The login information for user {" + userName + "}, is invalid."),
      new FaultCode("AccessDenied"));
            }
        }

        class STSAuthPolicy : IAuthorizationPolicy
        {
            // member variables
            string id;
            ClaimSet issuer = null;       
                   
            public STSAuthPolicy()
            {
                id = Guid.NewGuid().ToString();
            }

            #region IAuthorizationPolicy Members

            public bool Evaluate(EvaluationContext evaluationContext, ref object state)
            {
                Console.WriteLine("Call to STSAuthPolicy::Evaluate");
                List<Claim> claims = new List<Claim>();

                foreach (ClaimSet cs in evaluationContext.ClaimSets)
                {
                    if (cs.Issuer != this.Issuer)
                    {
                        Console.WriteLine("Processing ClaimSet from Issuer: {0}", cs.Issuer.ToString());
                        foreach (Claim c in cs)
                        {
                            if (cs.Issuer.FindClaims(ClaimTypes.System, Rights.Identity).GetEnumerator().MoveNext())
                            {
                                // these are system issued claims
                                Console.WriteLine("\tFound System Claim: " + c.ToString());

                                // if this is a Custom Username Claim
                                if (c.ClaimType == ClaimTypes.Name && c.Right == Rights.Identity)
                                {
                                    // implementation not shown, but just adds claims with 
                                    // custom claim types that our service auth policy understands
                                    AddUserIDClaimForUser(claims, (string)c.Resource);
                                    AddRoleClaimsForUser(claims, (string)c.Resource);
                                }
                            }
                        }
                    }
                }

                if (claims.Count > 0)
                {
                    evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, claims));
                    return true;
                }
                else
                    return false;
            }

            public ClaimSet Issuer
            {
                get
                {
                    if ( issuer == null )
                    {
                        List<Claim> claims = new List<Claim>();
                        claims.Add ( Claim.CreateNameClaim ( this.GetType().ToString()));
                        issuer = new DefaultClaimSet ( claims );
                    }

                    return issuer;
                }
            }

            #endregion

            #region IAuthorizationComponent Members

            public string Id
            {
                get { return id; }
            }

            #endregion
        }

    Is there something inherently wrong with this approach?  It seems far simpler to deal with than the approach you mentioned....

     

  • Friday, October 20, 2006 12:00 AMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    What the best way is depends on what you're trying to accomplish; the approach you take in the code above is probably a good one in most cases.  I think this one is a bit of an exception.  Installing a custom authenticator is indeed more complicated than doing claim set manipulation from an auth policy, but it's also desirable for Peter to avoid multiple hits to the user database.  It's also desirable to keep the service hardened against username/password dictionary attacks by hoisting validation as early in the processing chain as possible.  Is the extra code worth these benefits?  In a demo or prototype, probably not.  In a production app, probably yes, even if premature optimization is the root of all evil. 

    In general, whether it makes sense to do transformation from authentication specific claims to more abstracted claims like roles in an authenticator depends on the relation between the claims obtained by validation procedure and the authentication policy actioning them.  With say, windows mapped usernames or X509 certificates, roles likely map to the group SIDs obtained by WCF during authentication.  Hence there's little need to get involved with the authenticator because the authenticator provides a fair amount of actionable data in the claims it returns.  With username authentication via custom validator or membership provider WCF provides very few claims by default.  In my opinion it's natural to address this by modifying the authenticator to provide more detailed claims.  Doing so provides a more consistent information yield from authentication which, hopefully, allows for a cleaner separation between authentication and authorization and simplifies subsequent claim processing.

  • Friday, October 20, 2006 2:25 AMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Installing a custom authenticator is indeed more complicated than doing claim set manipulation from an auth policy, but it's also desirable for Peter to avoid multiple hits to the user database.

    Sure, but there is no reason why the approach outlined above includes more hits to the database than your proposed approach, the two hits are just separated in time.  With things like connection pooling and application model caching, I don't see the issue there.  Certainly the devil is in the details, but that's true for either approach.

    It's also desirable to keep the service hardened against username/password dictionary attacks by hoisting validation as early in the processing chain as possible

    How does your proposed solution solve this differently than the 'simpler' one?  That seems like a function of the authentication process, regardless of implementation...

    In my opinion it's natural to address this by modifying the authenticator to provide more detailed claims.  Doing so provides a more consistent information yield from authentication which, hopefully, allows for a cleaner separation between authentication and authorization and simplifies subsequent claim processing

    This facet of your solution is something I can agree with, for our case, we aren't utilizing the windows group information, but we do have a structure where the users can choose either username/password custom authentication or windows based authentication, so harmonizing the two approaches would be nice.  It won't likely save us any database work in the custom case, since we need to role lookup path either way, but it would make the two approaches more consistent.

     

  • Friday, October 20, 2006 11:34 AMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Thanks for feedback guys.. 

    So it's seems that if I want to avoid multiple lookups, that a Validator is not the way to go - I should be using an IAuthorisationPolicy.  Perhaps this is OK.. the result of the call to Issue is either an Authenticated or Unauthenticated token as opposed to an Authenticated token or AccessDenied exception.

    However I'm still confused..  My STS is creating the SamlToken within the Issue operation of the STS (which seems to be the pattern I've seen in all the STS implementations that I have looked at).. But this call obviously comes after both the Validator.validate and the AuthorisationPolicy.Evaluate. - how do I get from what you are suggesting to the GetIssuedClaims method that Issue calls?

    Perhaps I'm missing something in both your implementations as they don't seem to address my problem?

    - Is the STS implementation in the Federation example the pattern that should be used?

    - There seems to be so many choices around the security story (validators, authenticators, policies etc), they must have been designed with particular use cases in mind - my use case would seem to be standard: an STS authenticating against a DB - I find it hard to believe that the solution is so disjointed or convoluted?

    Anyway, thanks so far.. heres hoping the penny drops with me soon...

    Pete



  • Friday, October 20, 2006 2:38 PMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I believe it is up to the Authorization Policy on the STS to install the claims which are included as part of the SamlToken, at least that was the case in my example, and I think it's also the case in Todd's example, if I understand the flow correctly.  The validator and authenticator would add claims which could then be consumed by something like the STSAuthPolicy example I posted above.

     

  • Friday, October 20, 2006 5:26 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    There seems to be so many choices around the security story (validators, authenticators, policies etc), they must have been designed with particular use cases in mind - my use case would seem to be standard: an STS authenticating against a DB - I find it hard to believe that the solution is so disjointed or convoluted? 

    I think WCF's architecture has a pretty clean flow from authentication to authorization to app service code.  However, the boundaries between those three buckets are flexible and what you factor into each bucket is a function of the security policy you want to express, how you choose to factor the policy onto WCF, and various implementation tradeoffs.  There's certainly a feature hole for easily yielding claims from a username/password validator, but I wouldn't really say the design is built on a "for use case A go here" basis.

    Is the STS implementation in the Federation example the pattern that should be used?

    It's a pattern which should work reasonably well for most cases.  Probably including this one, but I don't feel I understand what you're doing well enough to pass judgement.

    Perhaps this is OK.. the result of the call to Issue is either an Authenticated or Unauthenticated token as opposed to an Authenticated token or AccessDenied exception.

    That's an important implementation detail to mention; if your STS doesn't need to reject unauthenticatable users you might as well flow the password into the auth context and do the DB lookup from the auth policy.

     

  • Friday, October 20, 2006 5:31 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Sure, but there is no reason why the approach outlined above includes more hits to the database than your proposed approach, the two hits are just separated in time.

    I think there are two options: 1) hit twice, once in the validator and once in the auth policy, and 2) hit once in the validator and yield claims for the auth policy to action from the authenticator.  To be clear, I'm suggesting the second.

    How does your proposed solution solve this differently than the 'simpler' one? 

    The validator's invoked much earlier than the auth policy.  A throw from the validator aborts subsequent processing and therefore reduces the cost of rejecting the message.  Not that this turns out to matter in Peter's case.

  • Friday, October 20, 2006 6:15 PMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I think there are two options: 1) hit twice, once in the validator and once in the auth policy, and 2) hit once in the validator and yield claims for the auth policy to action from the authenticator.  To be clear, I'm suggesting the second.

    In certain cases, this is true, assuming you can return all the information you need in a single database hit :).

    The validator's invoked much earlier than the auth policy.  A throw from the validator aborts subsequent processing and therefore reduces the cost of rejecting the message.  Not that this turns out to matter in Peter's case.

    I think I see what you were saying now, using the Validator approach avoids some of the overhead of WCF for rejected requests, at the expense of possibly introducing additional "database" traffic [I use the term loosely, since most folks these days seem to have some sort of object model/data access pattern in front of the actual database].  In either case, I don't see that as preventing dictionary attacks, or making the service more or less secure, maybe it makes DDoS attacks more difficult, but I wouldn't think it does so to a significant degree.

    Would you say that in situations where a large amount of "contextual work" or "WCF infrastructure" is needed that the Validator based approach may be more fitting, since the work required for setup is fairly high and can be avoided with the Validator vs. the Authenticator?  I'll have to do some performance testing to see what the performance difference between the two methods looks like.  Of course, this matters fairly little when dealing with an STS, since if everything is implemented properly, the traffic to the STS should be pretty low compared with the same authentication being bound directly to the service call.

     

  • Saturday, October 21, 2006 1:28 AMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
     TheJet wrote:

    In certain cases, this is true, assuming you can return all the information you need in a single database hit :).

    True.  Based on Peter's post I made that assumption for this particular case.

     TheJet wrote:

    Would you say that in situations where a large amount of "contextual work" or "WCF infrastructure" is needed that the Validator based approach may be more fitting, since the work required for setup is fairly high and can be avoided with the Validator vs. the Authenticator?  I'll have to do some performance testing to see what the performance difference between the two methods looks like.

    Did you mean the validator versus an authorization policy?  The username authenticator calls the validator directly, so about the only difference you'd see between throwing an authentication exception from the validator versus throwing from the authenticator is a function call.  That's not very much.  If you look at the authenticator/validator versus the auth policy how much of a difference you'll see will depend on the amount of processing the message requires.

     

  • Monday, October 23, 2006 11:23 AMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Just an update from my last posting, and comments on postings since...

    Todd West:
    I think WCF's architecture has a pretty clean flow from authentication to authorization to app service code.  However, the boundaries between those three buckets are flexible and what you factor into each bucket is a function of the security policy you want to express, how you choose to factor the policy onto WCF, and various implementation tradeoffs.  There's certainly a feature hole for easily yielding claims from a username/password validator, but I wouldn't really say the design is built on a "for use case A go here" basis.

    I have no doubt about the flexibility - I guess I'm still trying to "grok" where it is appropriate to do certain things with that model - more on this below

    Pete:
    Is the STS implementation in the Federation example the pattern that should be used?

    Todd:
    It's a pattern which should work reasonably well for most cases.  Probably including this one, but I don't feel I understand what you're doing well enough to pass judgement.

    I think what I am trying to do must be pretty standard:  I have a internet website, that users will "login" to, and their actions on the website will cause various back-end services to be called.  The services will be deployed accross multiple backend servers - so effectively I need single sign on accross the servers - hence why I am using an STS:  I want to validate and issue a token which contains a users permissions/roles accross the multiple backend servers and services.

    Pete:
    Perhaps this is OK.. the result of the call to Issue is either an Authenticated or Unauthenticated token as opposed to an Authenticated token or AccessDenied exception.

    Todd:
    That's an important implementation detail to mention; if your STS doesn't need to reject unauthenticatable users you might as well flow the password into the auth context and do the DB lookup from the auth policy.

    Ah, it's not so much about what it does/doesn't need to do..  I am adapting it's implmentation based on what I can or can't do in the various extension points through the exploration in this thread. It seems that if I decide to use a Validator (and throw AccessDenied in case of failure), then I _must_ do another DB lookup during the policy evaluation, or within the body of the "Issue" method of the STS service.  However, if I use a UserNameSecurityTokenAuthenticator and AuthorisationPolicy, then I can get away with one DB lookup (does it make sence to throw SecurityAccessDenied during the Evaluate of an AuthorisationPolicy?). 

    I personally think that throwing AccessDenied in the STS makes more sence than returning an empty token from the STS, as it would prevent the website from contacting the backend service with an empty token and putting unnecessary load on those services, so this choice _does_ matter in my case, but I need to get _something_ working.

    Todd: I think there are two options: 1) hit twice, once in the validator and once in the auth policy, and 2) hit once in the validator and yield claims for the auth policy to action from the authenticator.  To be clear, I'm suggesting the second.

    Are you sure this is what you mean?  within the Validator, I have no access to an EvaluationContext, so I cannot "yeild claims" for later in the pipeline.  However, the code you posted earlier in the thread is using an Authenticator yeilding to an AuthPolicy - so perhaps this is a typo? 

    Todd, towards the end of the thread, you seem to be favouring Validator, as it reduces the cost of of rejecting messages, yet valid auth requests would increase the load on the DB.

    In the end, what I implemented was similar to your original suggested code, Todd:  ServiceCredentialsTokenManager; UserNameSecurityTokenAuthenticator, and AuthorisationPolicy (where a call to the DB is made, and claims are set on the inbound message).  Then, within the Issue method of the service, I take the inbound claims and add them to the outbound token (this is something that had me confused for ages)

    I went with this approach in the end, as it seems to me, that the cost of calling a DB is so large, if someone is trying to DOS me, that it makes little diference if I call it within Validator.Validate or AuthPolicy.Evaluate..

    One final point, in my implementation, I make my DB call during my AuthPolicy Evaluate, and add the returned data to the EvaluationContext, so that during the service method "Issue", I can copy the incoming claims to the outgoing claims.  Is it approriate to throw a SecurityAccessDenied during the evaluate if authentication failed ?  Certainly authentication success does not seem to have anything to do with the return value from Evaluate?

    Sincerely

    Pete

     

  • Monday, October 23, 2006 4:53 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
     Peter McEvoy wrote:

    It seems that if I decide to use a Validator (and throw AccessDenied in case of failure), then I _must_ do another DB lookup during the policy evaluation, or within the body of the "Issue" method of the STS service.  However, if I use a UserNameSecurityTokenAuthenticator and AuthorisationPolicy, then I can get away with one DB lookup (does it make sence to throw SecurityAccessDenied during the Evaluate of an AuthorisationPolicy?). 

    I think there's some architectural confusion here.  The default UserNameSecurityTokenAuthenticator which ships with WCF HasA UserNamePasswordValidator which you can configure via ServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator.  If you install a custom authenticator you don't have to preserve the authenticator/validator factoring in your authenticator class.

     Peter McEvoy wrote:

    Are you sure this is what you mean?  Within the Validator, I have no access to an EvaluationContext, so I cannot "yeild claims" for later in the pipeline.  However, the code you posted earlier in the thread is using an Authenticator yeilding to an AuthPolicy - so perhaps this is a typo?

    I wrote "yield claims for the auth policy to action from the authenticator".  That's what I meant.    If you choose to preserve the authenticator/validator factoring in custom code you could modify the interface between the two objects to return whatever data you need.

     Peter McEvoy wrote:

    I went with this approach in the end, as it seems to me, that the cost of calling a DB is so large, if someone is trying to DOS me, that it makes little diference if I call it within Validator.Validate or AuthPolicy.Evaluate.

    It could be.  All depends on the cost of DB lookups and avoidable message processing.  If anybody has sufficient data to determine the best choice there it's you.

     Peter McEvoy wrote:

    One final point, in my implementation, I make my DB call during my AuthPolicy Evaluate, and add the returned data to the EvaluationContext, so that during the service method "Issue", I can copy the incoming claims to the outgoing claims.  Is it approriate to throw a SecurityAccessDenied during the evaluate if authentication failed ?  Certainly authentication success does not seem to have anything to do with the return value from Evaluate?

    You can certainly throw (though it's possible the client won't receive a security fault if you throw SecurityAccessDenied; I'd have to double check) but it might be simplest to have Evaluate() return no claims when authentication fails.  This should cause your CheckAccessCore() to return false and WCF will handle the rest.

  • Monday, October 23, 2006 6:02 PMTheJet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I think there's some architectural confusion here.  The default UserNameSecurityTokenAuthenticator which ships with WCF HasA UserNamePasswordValidator which you can configure via ServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator.  If you install a custom authenticator you don't have to preserve the authenticator/validator factoring in your authenticator class.

    That's strange, I could have sworn that in numerous discussions here that there was no access to any sort of context within the UserNamePasswordValidator.  If the validator was called in the fashion you describe, wouldn't that context be available through any of the numerous static properties out there that provide access to the current context [e.g. ServiceSecurityContext]?  Or is just the case that none of those static properties support adding additional information to the context, or that the security parts execute so early in the pipeline that none of these things are yet setup?  The latter would seem to make the most sense, can you confirm that this is in fact where the limitation is?  If there is some sort of context available at the time of the Validator execution, what types of context are available [IChannelContext?]?

    I know there have been issues posted to the forum in the past that showed that certain bindings, like basicHttpBinding will ignore custom username/password authenticators completely.  So the followup question would be, does the method you propose work for all bindings, or only for custom bindings?  It would seem that, based on the research that I've done into the basicHttpBinding classes, that the decision was actually made in the binding class, and not in something you could easily override. [ref: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=768413&SiteID=1]  I guess the main question here is, what portions of the configuration that you've posted above are required to use this method and get the appropriate bits called?  It looks like you're using transport security with the UserNameForSsl setting, is this same sort of approach applicable for things like UserNameForCertificate custom bindings?

     

  • Monday, October 23, 2006 11:48 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
     TheJet wrote:

    I could have sworn that in numerous discussions here that there was no access to any sort of context within the UserNamePasswordValidator.

    That's correct.  A username/password authenticator yields claims by way of the IAuthorizationPolicy returns from ValidateUserNamePasswordCore().  The authorization context is not available at authentication time.

    Interesting.  I think you've mistaken the pivot though; it's not the binding but the type of security used by the binding, which is a function of how its knobs are turned.  For example, if you use new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential) then the username/password authenticator/validator will be invoked.  The discussion in this thread should apply to any binding which uses message security to carry username/password credentials.

  • Wednesday, August 08, 2007 1:34 PMTaavi KoosaarMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Todd,

     

    Im implementing the functionality, you have post in the start of this thread. Everything is nice and seems it solves the problem i have - i want certain data to be given forward to the policy.

     

    This however raises two questions for me:

     

    1. Do the policies that are specified in the configuration also get applied after i have coded in to add the policy in the authenticator.

    2. There is a possibility to create configurationhandler for the clientcredentials. I am unable to do the same for this ServiceCredentials. Id like to be able to add this behaviour through configuration.

    Note that the documentation (Windows SDK Doc) says that:

    Add support for configuration using the steps described above in the procedures "Creating a configuration handler for custom client credentials" and "Registering and using a custom client credentials configuration handler in the application configuration." The only difference is to use the ServiceCredentialsElement class instead of the ClientCredentialsElement class as a base class for the configuration handler. The custom service credential element can then be used wherever the system-provided <serviceCredentials> element is used.

     

    The text is located on the page: "How To: Create Custom Client and Service Credentials "

     

    However, the ServiceCredentialsElement class is sealed, so i cannot inherit from it.

     

    Also note that, there should be a possibility to save  context data somewhere or add Custom Identity object to somewhere in the Authentication level, if credentials are correct.

    At the moment WCF is just creating an IIdentity with a name property, this is hardly enough.

     

    If we could somehow add our own Custom Identity class in the authentication (CustomUserNamePasswordValidator), then that would be pretty helpful.

    Is there a way to add our own Identity, so that the evaluation context would have our custom one?

     

    Regards,

    Taavi

  • Wednesday, August 08, 2007 2:00 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

     Taavi Koosaar wrote:
    Do the policies that are specified in the configuration also get applied after i have coded in to add the policy in the authenticator.

     

    I'm not clear on which policies you're referring to.  If you're asking about external authorization policies or a SerivceAuthorizationManager the answer is yes.

     

     Taavi Koosaar wrote:
    However, the ServiceCredentialsElement class is sealed, so i cannot inherit from it.

     

    This is fixed in Orcas.

     

     Taavi Koosaar wrote:
    Is there a way to add our own Identity, so that the evaluation context would have our custom one?

     

    Set the Identities property on the auth policy returned from the authenticator.  A quick search will turn up the many threads discussing this.

  • Wednesday, August 08, 2007 4:03 PMTaavi KoosaarMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thanks for a quick reply Smile

     

    I meant the policies that you add through configuration under serviceBehaviour -> serviceAuthorization.

     

    <serviceAuthorization principalPermissionMode="Custom">

    <authorizationPolicies>

    <add policyType ="STS_Host.DemoAuthPolicy2, STS_Host"/>

    <add policyType ="STS_Host.DemoAuthPolicy, STS_Host"/>

    </authorizationPolicies>

    </serviceAuthorization>

     

    If those policies here, will be applyed, then the policies in the authenticator are merely addisions. Which is great Smile

     

    With the Identity, i meant adding it in the CustomUserNamePasswordValidator.

    public class CustomUsernamePasswordValidator : UserNamePasswordValidator

    {

    public override void Validate(string userName, string password)

    {

    //Do validation ... and if credentials are valid then create custom identity for authorization evaluation

     

    SomeContext.Properties["Identities"].Add(new MyCustomIdentity(userName, password, otherStuff));

    }

    }

     

     

    Because thats the place im doing authentication and thats the place the identity should be bourn, right? In the authorizationpolicy, i do not have any access to the username/password, unless of course i write my custom code.

    Although for such a simple case, creating a seperate authenticator is not that pleasent. Because all i want to do is to authenticate those 2 credentials and then create the correct authenticated Identity.

     

    Its good to hear, that in Orcas the class is no longer sealed. Unfortunately, since Orcas is not due in a few months time, this offers me less comfort. Since i have my WCF services largely configuration based. Id like to keep them managable by configuration. Thats one of this great about the WCF.

     

    Taavi

  • Thursday, August 09, 2007 7:33 AMTaavi KoosaarMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     

    So i have been playing with the code a bit more and more questions have pumped up. Hopefully, you dont mind this

     

    Firstly, a note to others. With ServiceCredentials, you cant add some in config and some in code.

    All servicecredentials need to be added in code, if you cannot configure them. I had to delete my servicecredentials section from the config, before the ones i added in code, started to work.

     

    Firstly, the code indeed works as i wish it to and require Smile But i noticed an odd behaviour, the policy i added in code, its Evaluate method was executed twice. Both times it added claims to the evaluationcontext. Oddly enough, only one claimset was in the context, just like there would be two evaluationcontextes or the first one wasnt quite the correct one. Also note, that the authenticator policy is run first Smile

     

    So my question is:

    Is there a reason the Evaluation method would be run twice, even if yuo return True from it (the true meaning evaluation is successful) ?

     

    I have run the STS in debug mode for several times, and it always executes twice.

     

    Note: i tryed adding another policy in the authenticator, to see if im delusional. Both policies evaluation method was executed twice.

     

  • Thursday, August 09, 2007 8:56 AMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi all,
    I started the thread quite some time ago, and I must say that in this time, I am (realtively) none the wiser about the "pattern" that the security model is supposed to use..  The examples I see in the wild (or indeed with WCF SDK) seem to be contrived or even "edge" use-cases, and I have not found one that solves my "internal-federation" use case.

    Yes, we did get something working and it hasn't changed much in all this time:  We dropped the idea of a validator, and went with an _explicit_ STS contract [IE: Token Login(username, password); Token Renew(token); etc] against our "security token service" rather than using WS-Federation (but then our system is self contained and does not need to federate over the internet with other systems in a standards compliant way)... 

    Once we get a Token (a custom object that wraps a signed byte[] of user id data) that Token is added to our (outgoing) service calls in the soap header using a MessageInspector (which is added to the runtime stack via an IContractBehavior). 

    Then, on the service side, the token is converted to a thread identity using AuthorizationPolicy and the "Principal" property of the evaluation context.

    However, I'm still not entirely sure of the "runtime contract" that Authorization policies are supposed to honour and how they interact with the ServiceAuthorizationManager.  Is it their responsibility to throw a SecurityException if Evaluate doesn't like what it processes? 

    We've implemented our own ServiceAuthorizationManager and overridden CheckAccessCore and in this we check roles for accessing certain methods (again, we have a custom attribute in our contract that says what roles are required for accessing given methods) - but this is messy too, as all we have is the operation URN from the OperationContext, and no access to the contract, so we need to reflectively load the assembly (guessing the name from the URN) and find out what (custom) role attributes have been applied at the contract level.    Why do this and not use PrincipalPermission attribute?  well, in my mind, security should be expressed at the Contract level so that clients and servers can honour it, and as far as I recall PrincipalPermission attribute can only be applied at a Class level on the service implementation.

    Anyway, I'm sure there is more than one way to skin the security cat - I just wish I had a pattern that I could follow as tried and trusted...

    Pete
  • Thursday, August 09, 2007 3:38 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     Taavi Koosaar wrote:
    With the Identity, i meant adding it in the CustomUserNamePasswordValidator.  Because thats the place im doing authentication and thats the place the identity should be born, right? In the authorizationpolicy, i do not have any access to the username/password, unless of course i write my custom code.

     

    I agree it's cleanest to only plug in at one point.  However, doing everything you want to do from one extensibility point will require plugging in custom code since, as discussed at the start of this thread, there's no way to return an auth policy from the validator.  There's nothing wrong with composing policies so long as good design practices are followed; think of it as being like structuring a class hierarchy.

     

     Taavi Koosaar wrote:
    With ServiceCredentials, you can't add some in config and some in code.

     

    I think you can; can you share a repro?

     

     Taavi Koosaar wrote:
    Is there a reason the Evaluation method would be run twice, even if you return True from it (the true meaning evaluation is successful)?

     

    It's been a while since I looked at this but IIRC what happens is all policies are run until an entire iteration occurs where no claims are added to the auth context.  This gives policies a chance to react to other policies.

     

     Peter McEvoy wrote:
    as far as I recall PrincipalPermission attribute can only be applied at a Class level on the service implementation.

     

    Actually, it's the other way around.  The rest of your post is interesting, but I'm not quite sure what feedback to take away from it.  While I agree the docs on WCF's auth implementation should be improved, the overall message I'm getting is one of "we chose, for the most part, not to use the security features WCF ships with and aren't quite sure how we feel about having written our own code instead".  If that's not in the right direction please correct me.

     

     Peter McEvoy wrote:
    Is it their responsibility to throw a SecurityException if Evaluate doesn't like what it processes?

     

    I believe it's more typical to cause CheckAccessCore to return false.

  • Thursday, August 09, 2007 5:12 PMPeter McEvoy Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Sorry Todd, I guess I wasn't very constructive in my critism...  I guess what you can take from the post is that "I did not understand how to use the security features that ship with WCF and felt I would get better control by rolling our our own".  Sounds like a classic case of "not invented here"?  perhaps.  But I think we tried to adapt the Federation example for sometime before deciding to go with our own.

    My typing mistake about PrincipalPermission attribute:  when I mentioned Class, I meant the attribute is applied to the methods within the service implmentation class (as detailed in the link you sent) - It felt better (from a client contract POV) to specify the required permissions on the methods within the contract _interface_ . I should add, that we like to use a UML tool to specify our service interface contracts, and like to capture as much highlevel information in that tool - rather than in code implementation.  We then generate our WCF contract interfaces directly from the tool.  Security roles and permissions feel more like a design time specification (by the system designer) rather than implmentation time (by a developer).

    WRT my (and your) point about AuthorisationPolicies and ServiceAuthorisation manager and SecurityException: what is confusing is the interaction between the two classes and who's responsibility it is to do things:  currently we use the authorisation policy to set a thread identity, and then within CheckAccessCore we validate that the identity has rights to do whatever it is trying to do (and returning the correct bool).  What was not obvious was that it was necessary to subclass BOTH of those classes. I guess I would like the idiots guide to the usage pattern.

    Once again, sorry for being negative long day and the penny still hasn't dropped..

    Pete
  • Friday, August 10, 2007 8:17 AMTaavi KoosaarMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     

    Regarding the ServiceCredentials, it is not that easy to repro (meaning i cant give the code). Hopefully this would do.

     

    Here is the config i have:

     

    <serviceBehaviors>

    <behavior name="stsBehavior">

    <serviceDebug includeExceptionDetailInFaults ="true"/>

    <serviceAuthorization principalPermissionMode="Custom">

    <authorizationPolicies>

    <add policyType="Some.Authorization.ClaimsAuthorizationPolicy, Some.Authorization"/>

    </authorizationPolicies>

    </serviceAuthorization>

    <serviceCredentials>

    <serviceCertificate findValue="IPKey" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />

    </serviceCredentials>

    </behavior>

    </serviceBehaviors>

     

    And here is the ServiceHost code and result i get when running it.

     

    http://melborp.net/files/blog/exception_adding_serviceCredentialInCode.png

     

     

    Now regarding the Evaluation method. I understand, that the method work iteratively. I understand, that if i return true from the policy, then this policy will not be applyed again, right? (policy meets the requirements, so i return true).

     

    OK, well in the case im describing here, is that the policy that is added in the Authenticator, its Evaluation mehod is called twice. Although, the first time is enough and i do return true even the first time. The goal of that policy for me, is to only add the Identity to the evaluation context.

    What makes this even stranger, is that although i add the Identity to the evaluationcontext the first time, the second time it launches, the evaluationcontext doesnt have Identities property again and it adds again.

    OK, adding the identity itself is no performance issue. Im just wondering, if this is the normal behaviour, because it doesnt sound to me.

    Is there any special behaviour, when you add the policy in the Authenticator? Because this does not happen with the policies added in the configuration.

     

    To repro, make a service that is using custom servicecredentials (basicly same code you have in this post). In the authenticator, add two policies.

    Add the serviceCredentials to the services, add a brakepoint to the Evaluation methods in both policies.

    Amaze, why the Evaluation of each policy is called twice and the context is different (add something to the evaluationcontext to differenciate that the context is not the same the second time its launched - like in one policy add the identities property to the context).

     

    This is like a special behaviour of policies added in the authenticator, not sure why. And again, i return True every time and i also add something to the context, but the values are not there on second launch.

     

    To Peter McEvoy

    Have you  seen this post - http://www.theserverside.net/tt/articles/showarticle.tss?id=ClaimsBasedSecurityModel2

     

    Realy good to creating claims based security model Smile Perhaps helps you.

    Note: There is a part one as well.

     

  • Friday, August 10, 2007 7:05 PMTodd West - Microsoft Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
     Taavi Koosaar wrote:
    Regarding the ServiceCredentials, it is not that easy to repro (meaning i cant give the code).

     

    I think I understand.  Probably what you want is something like

     

    ServiceCredentials fromConfig = serviceHost.Description.Behaviors.Remove<ServiceCredentials>();

    serviceHost.Description.Behaviors.Add(new UserNameServiceCredentials(fromConfig));

     

    with

     

    public UserNameServiceCredentials(ServiceCredentials fromConfig) : base(fromConfig) { ... }

     

     Taavi Koosaar wrote:
    Is there any special behaviour, when you add the policy in the Authenticator? Because this does not happen with the policies added in the configuration.

     

    Interesting; I'll look into this.

     

     Peter McEvoy wrote:
    It felt better (from a client contract POV) to specify the required permissions on the methods within the contract _interface_ .

     

    That is a problem with layering a service implmentation on top the interface.  It is possible to remove the interface by marking up the service class directly but, as you point out, it's usually preferable to configure permissions at deployment time rather than hard coding them at design time.  Claims based authorization is, in part, intended to provide an alternative to the inflexibility of attributes.


     Peter McEvoy wrote:
    What was not obvious was that it was necessary to subclass BOTH of those classes. I guess I would like the idiots guide to the usage pattern.

     

    What would be most useful to you?  Better docs?  Deeper samples?  Whitepapers?  AzMan?  Something else?

  • Thursday, July 17, 2008 7:50 PMKevon Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I've read and re-read this article about 30 times now and am having a hard time wrapping my brain around it.  I *think* I am trying to do something similar to what is being described here. 

     

    This is what I am doing:

     

    I have this defined in my serviceBehavior

     

    <userNameAuthentication customUserNamePasswordValidatorType="MyUsernamePasswordValidator, TokenService"

    userNamePasswordValidationMode="Custom" />

    <serviceCertificate findValue="CN=STSAuthority" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName"/>

     

    I have this implemented as well

     

    public class MyUsernamePasswordValidator : UserNamePasswordValidator

    {

    public override void Validate(string userName, string password)

    {

    // code removed for simplicyt, but make a database call and get a row back with information about

    // the user in question.  What is their address, phone number, etc.

    Object obj = GetPersonalInfo(userName, password);

    }

     

    What I NEED to do is return that object in the SAML token.  Can this be done.