authn vs. authz


John Dennis
 

Hi Liem:

Thank you for sending out the sequence diagrams, they've been very
helpful. Also thank you for posting the code to a public git repo. The
code looks clean, nicely organized and professionally written. I've been
going through the code to get a better understanding of the overarching
architecture and I've got a few questions.

My first question is an organizational one, I noticed you've been
sending your emails with design information to specific individuals
instead of the aaa-dev list, is there a reason? FWIW I've sent this mail
to both the individuals you've been emailing *and* the aaa-dev list.
Should we be using the aaa-dev list from this point on?

The Framework Overview (https://github.com/opendaylight/aaa) is clear
that authentication (authn) and authorization (authz) are two
independent concepts and derive from independent sources of authority.
This is good, authn and authz should be separate.

But when I look at the code it looks to me as if authn and authz have
been conflated. I draw this conclusion by looking at the fields in the
Claim and Authentication types. An identity claim is something returned
by a trusted IdP (Identity Provider) which attests to the identity and
attributes bound to that identity by the IdP. It appears as if the Claim
type is being used for this purpose in the code. However the Claim type
also includes tenant and role information. An independent IdP will not
(or should not) have information specific to ODL. This is especially
true for roles, only ODL should know what the roles are and which
identities possess those roles. [1]

Perhaps I've misread the code (please correct me) but it looks as if
ClaimAuthFilter via the ClaimAuth.transform() method is supposed to map
from an IdP identity assertion to a Claim object. What is confusing me
is how or why would an external authn assertion know anything about the
ODL roles in order to populate the roles in the Claim object? [2]

It seems to me there needs to be a separate mapping stage which maps
from an identity assertion to ODL specific information such as tenant
and roles. As an example you might want to look at how Keystone handles
the federated case
(https://github.com/openstack/identity-api/blob/master/v3/src/markdown/identity-api-v3-os-federation-ext.md).
In the Keystone federation architecture one binds an (IdP, protocol)
2-tuple to a mapping which maps from IdP attributes to those used
internally (i.e. groups, roles, etc.)

Going back to the code and the sequence diagrams shouldn't there be an
IdentityClaim (does not yet exist) which is passed to a mapping endpoint
(does not yet exist) which returns a Claim instead of the
ClaimAuthFilter attempting to assign roles and return a Claim?

Also, I'm not sure why we have the DirectAuth case as a special case
code path and flow. Couldn't the code be simplified if DirectAuth was an
instance of the federated case? Here the internal DirecAuth "toy" IdP
only does username/password authn and the roles are provided by a
mapping? Fewer code paths usually means more robust code.

I'm sure I have a slew of misunderstandings about how the actually code
works :-) Feel free to set me straight.

Thanks again for the great code and excellent diagrams!

John


[1] Allowing an IdP to attach a role to an identity is a security
concern. You may trust an IdP to authenticate a user but do you really
want to trust that IdP to also claim that user has the admin role in
your service? It may be case that you trust *some* IdP's to assign roles
but that should be configurable and off by default. I suspect the
DirectAuth case is one such example (correct?)

[2] It almost looks as if the authz processing is supposed to happen in
TokenEndpoint.createAccessToken() where the else clause says

// TODO: Support authorization code later...

but if the claim filters are setting the roles (which is my definition
of authz) then what authorization code is going to execute here?
--
John


Nguyen, Liem Manh <liem_m_nguyen@...>
 

Hi John,

 

My response in-line below…   

 

Cheers,

Liem

 

-----Original Message-----
From: John Dennis [mailto:jdennis@...]
Sent: Monday, June 16, 2014 3:39 PM
To: Nguyen, Liem Manh; Abhishek Kumar; 'Arash Eghtesadi'; Lakshman Mukkamalla; Lenrow, Dave; Mellquist, Peter; Wojciech Dec; aaa-dev@...; Nathan Kinder
Subject: authn vs. authz

 

Hi Liem:

 

Thank you for sending out the sequence diagrams, they've been very helpful. Also thank you for posting the code to a public git repo. The code looks clean, nicely organized and professionally written. I've been going through the code to get a better understanding of the overarching architecture and I've got a few questions.

 

My first question is an organizational one, I noticed you've been sending your emails with design information to specific individuals instead of the aaa-dev list, is there a reason? FWIW I've sent this mail to both the individuals you've been emailing *and* the aaa-dev list.

Should we be using the aaa-dev list from this point on?

 

>> Yes, I was not sure if everyone has subscribed to the aaa-dev list; so, I sent to individual addresses to make sure that the information does get to our team.  If everyone has got on the aaa-dev list (which I encourage folks to), it will make it simpler next time J

 

The Framework Overview (https://github.com/opendaylight/aaa) is clear that authentication (authn) and authorization (authz) are two independent concepts and derive from independent sources of authority.

This is good, authn and authz should be separate.

 

But when I look at the code it looks to me as if authn and authz have been conflated. I draw this conclusion by looking at the fields in the Claim and Authentication types. An identity claim is something returned by a trusted IdP (Identity Provider) which attests to the identity and attributes bound to that identity by the IdP. It appears as if the Claim type is being used for this purpose in the code. However the Claim type also includes tenant and role information. An independent IdP will not (or should not) have information specific to ODL. This is especially true for roles, only ODL should know what the roles are and which identities possess those roles. [1]

 

>> From a third-party IdP, the incoming assertion is in the form of Map<String, Object> which is a collection of Servlet attributes and HTTP headers, which ODL will not understand.  In order to normalize this into an ODL “Claim” object that ODL can understand, an implementation of the ClaimAuth interface needs to transform the external claim into the ODL Claim object.  This transformation responsibility includes figuring out what roles user Joe has in what domain under ODL, or may be Joe is actually Bob in ODL.  The Authentication object is simply meant to represent the authentication context to be exposed to the service layer and includes an expiration.

 

Perhaps I've misread the code (please correct me) but it looks as if ClaimAuthFilter via the ClaimAuth.transform() method is supposed to map from an IdP identity assertion to a Claim object. What is confusing me is how or why would an external authn assertion know anything about the ODL roles in order to populate the roles in the Claim object? [2]

 

It seems to me there needs to be a separate mapping stage which maps from an identity assertion to ODL specific information such as tenant and roles. As an example you might want to look at how Keystone handles the federated case (https://github.com/openstack/identity-api/blob/master/v3/src/markdown/identity-api-v3-os-federation-ext.md).

In the Keystone federation architecture one binds an (IdP, protocol) 2-tuple to a mapping which maps from IdP attributes to those used internally (i.e. groups, roles, etc.)

 

Going back to the code and the sequence diagrams shouldn't there be an IdentityClaim (does not yet exist) which is passed to a mapping endpoint (does not yet exist) which returns a Claim instead of the ClaimAuthFilter attempting to assign roles and return a Claim?

 

>> You are correct that the ClaimAuth::transform() maps the identity assertion into a Claim object.  While an external AuthN assertion does not know anything about ODL roles, the specific ClaimAuth implementation should know how to extract the external AuthN assertion information and any additional attributes needed to map that particular IdP protocol onto ODL roles/domain.  Sure, it could use a mapping service like you mentioned underneath the hood.  We could even have a generic mapping service like Keystone (thanks for the link, BTW), but to keep it simple for Helium, I am thinking we can just have a mapping service specific to SSSD, since our goal is to support SSSD, unless someone has the bandwidth to implement a generic mapping service/API—which I would be a fan of!

 

Also, I'm not sure why we have the DirectAuth case as a special case code path and flow. Couldn't the code be simplified if DirectAuth was an instance of the federated case? Here the internal DirecAuth "toy" IdP only does username/password authn and the roles are provided by a mapping? Fewer code paths usually means more robust code.

 

>> The internal IdM provides 2 main functions:  authorization (what roles does this user have in what domain?) and identity assertion (is this the user he claims to be with the given credentials?).  Direct AuthN involves both functions of the internal IdM, while the federated case involves only the first one.  Hence, we have 2 separate interfaces to call out these differences.  As you can tell, I am a fan of using separate Java interfaces to enforce/express contracts J.

 

I'm sure I have a slew of misunderstandings about how the actually code works :-) Feel free to set me straight.

 

Thanks again for the great code and excellent diagrams!

 

John

 

 

[1] Allowing an IdP to attach a role to an identity is a security concern. You may trust an IdP to authenticate a user but do you really want to trust that IdP to also claim that user has the admin role in your service? It may be case that you trust *some* IdP's to assign roles but that should be configurable and off by default. I suspect the DirectAuth case is one such example (correct?)

 

[2] It almost looks as if the authz processing is supposed to happen in

TokenEndpoint.createAccessToken() where the else clause says

 

// TODO: Support authorization code later...

 

but if the claim filters are setting the roles (which is my definition of authz) then what authorization code is going to execute here?

--

John


John Dennis
 

On 06/16/2014 07:49 PM, Nguyen, Liem Manh wrote:

Hmm... for some reason my email client (Thunderbird) is having trouble
quoting your message in my reply (your text is a single long line that
Thunderbird wants to truncate) so I'm going to do some manual cut-n-paste.


You are correct that the ClaimAuth::transform() maps the identity
assertion into a Claim object. While an external AuthN assertion
does not know anything about ODL roles, the specific ClaimAuth
implementation should know how to extract the external AuthN
assertion information and any additional attributes needed to map
that particular IdP protocol onto ODL roles/domain. Sure, it could
use a mapping service like you mentioned underneath the hood. We
could even have a generic mapping service like Keystone (thanks for
the link, BTW), but to keep it simple for Helium, I am thinking we
can just have a mapping service specific to SSSD, since our goal is
to support SSSD, unless someone has the bandwidth to implement a
generic mapping service/API—which I would be a fan of!
OK, but here is my concern. The ClaimAuth filter is Java code, if I'm
understanding you correctly you're suggesting hardcoding business logic
of how to map external IdP properties into ODL properties. I don't see
how hardcoding that logic is viable.

Suppose the logic is bob@... is assigned the admin role. What
happens when Bob leaves or Sally is added as an admin? Do we have to
edit the Java filter code?

It seems to me the ClaimAuth filter has to rely on some loadable mapping
resource. But once you have the mapping support the game changes, see
below ...

The internal IdM provides 2 main functions: authorization (what
roles does this user have in what domain?) and identity assertion (is
this the user he claims to be with the given credentials?). Direct
AuthN involves both functions of the internal IdM, while the
federated case involves only the first one. Hence, we have 2
separate interfaces to call out these differences. As you can tell,
I am a fan of using separate Java interfaces to enforce/express
contracts J.
If you have a IdM -> ODL mapping facility then you don't need 2 distinct
implementations. The direct auth case is an instance of an external IdM
and you've eliminated a significant amount of code to author and verify
is correct.


--
John


Nguyen, Liem Manh <liem_m_nguyen@...>
 

Hi John,

I don't suggest hard-coding mapping logics... It should be some sort of JSON mapping file; there just won't be any API for it, unless someone has the bandwidth. For user/role assignment, we use the internal IdM APIs--Peter perhaps can go through that with us at the next presentation.

The direct auth case is an instance of an external IdM
Perhaps, we have a mix-up of words here... What I mean by direct auth is that there is no external IdP (to distinguish from federation which means external IdP).

Liem

-----Original Message-----
From: John Dennis [mailto:jdennis@...]
Sent: Tuesday, June 17, 2014 7:15 AM
To: Nguyen, Liem Manh; Abhishek Kumar; 'Arash Eghtesadi'; Lakshman Mukkamalla; Lenrow, Dave; Mellquist, Peter; Wojciech Dec; aaa-dev@...; Nathan Kinder
Subject: Re: authn vs. authz

On 06/16/2014 07:49 PM, Nguyen, Liem Manh wrote:

Hmm... for some reason my email client (Thunderbird) is having trouble quoting your message in my reply (your text is a single long line that Thunderbird wants to truncate) so I'm going to do some manual cut-n-paste.


You are correct that the ClaimAuth::transform() maps the identity
assertion into a Claim object. While an external AuthN assertion does
not know anything about ODL roles, the specific ClaimAuth
implementation should know how to extract the external AuthN assertion
information and any additional attributes needed to map that
particular IdP protocol onto ODL roles/domain. Sure, it could use a
mapping service like you mentioned underneath the hood. We could even
have a generic mapping service like Keystone (thanks for the link,
BTW), but to keep it simple for Helium, I am thinking we can just have
a mapping service specific to SSSD, since our goal is to support SSSD,
unless someone has the bandwidth to implement a generic mapping
service/API-which I would be a fan of!
OK, but here is my concern. The ClaimAuth filter is Java code, if I'm understanding you correctly you're suggesting hardcoding business logic of how to map external IdP properties into ODL properties. I don't see how hardcoding that logic is viable.

Suppose the logic is bob@... is assigned the admin role. What happens when Bob leaves or Sally is added as an admin? Do we have to edit the Java filter code?

It seems to me the ClaimAuth filter has to rely on some loadable mapping resource. But once you have the mapping support the game changes, see below ...

The internal IdM provides 2 main functions: authorization (what roles
does this user have in what domain?) and identity assertion (is this
the user he claims to be with the given credentials?). Direct AuthN
involves both functions of the internal IdM, while the federated case
involves only the first one. Hence, we have 2 separate interfaces to
call out these differences. As you can tell, I am a fan of using
separate Java interfaces to enforce/express contracts J.
If you have a IdM -> ODL mapping facility then you don't need 2 distinct implementations. The direct auth case is an instance of an external IdM and you've eliminated a significant amount of code to author and verify is correct.


--
John