Passing data from auth source to authproc filter

980 views
Skip to first unread message

Ben McClure

unread,
Aug 22, 2011, 4:53:30 AM8/22/11
to simple...@googlegroups.com
I'm having trouble getting data from my authsource to my authproc filter.

I have developed a simple SQL-based replacement for the multiauth module, which just like the module its based on, it stores the actual authsource id that was used to log in in a session variable.

I don't seem to have access to that session variable during my authproc filter, however--the value I get returned from the $session->getData function, using the same type and key as my authsource, always comes up empty.

I tried instead saving the variable to the $state object, but then I realized something--after a user authenticates with an authsource and then tries to log in at the idP again next time while still authenticated, the value was not re-saved to the $state object, so the authproc filter choked because it could not figure out which authsource was actually used. Normally re-authentication shouldn't be needed I don't think, but it happens whenever I try to test the idP and then test it again afterward.

So I can't seem to access the session variable saved by the authsource, and I can only access the state variable upon initial login (or after logging out or clearing sessions). Is there a better way to get this piece of information to my authproc filter?

Thanks!

Ben

Ben McClure

unread,
Aug 22, 2011, 4:56:12 AM8/22/11
to simple...@googlegroups.com
Oh, and just to make sure I wasn't doing something wrong, I tried to use $session->setAttribute() and $session->getAttribute() but the attribute value that I set in the authsource is always coming up blank in the authproc filter--do they utilize different sessions or something? I am sure I read that the authproc filter happens after authentication and before returning to the SP, so the value should be in the session, right?

Ben

Ben McClure

unread,
Aug 22, 2011, 6:08:34 AM8/22/11
to simple...@googlegroups.com
To back up what I'm saying with some code:

My authsource calls the following immediately after the user chooses an authentication source:

$session = SimpleSAML_Session::getInstance();
$session->setAttribute('InternalAuthId', $authId);

My authprov filter then tries to retrieve the value in its process(&$state) function like this:

$session = SimpleSAML_Session::getInstance();
$authId = $session->getAttribute('InternalAuthId');

if (empty($authId)) {
throw new SimpleSAML_Error_Exception('Internal AuthId not found in session.');
}

That exception gets thrown every time, however.

Am I doing something wrong here? Thanks,

Ben

Ben McClure

unread,
Aug 22, 2011, 7:11:41 PM8/22/11
to simple...@googlegroups.com
I'm still very confused about what I'm doing wrong--Sorry my posts have been so long-winded, but is there anyone who could help me figure out the proper way to store a piece of data along with the authentication information so that it can be read from one of my authproc filters?

I've gone over my code again and again and I seem to be doing the same thing to get the session data in my authproc filter that I am in my authsource, and it seems to work fine in my authsource, but always comes up empty in my authproc filter...

Thanks for reading this far, and thanks a hundred times over if anyone can help me get past this little hurdle :)

Ben

Ben McClure

unread,
Aug 22, 2011, 7:51:52 PM8/22/11
to simple...@googlegroups.com
I gave in and just saved it in the $state['attributes'] array instead. I would prefer not to intermingle internal properties with user attributes, but this at least works for now...

Ben

Ben McClure

unread,
Aug 22, 2011, 8:40:05 PM8/22/11
to simple...@googlegroups.com
I take that back--I worked around it another way, but I just realized, even when I set the $state['attributes']['authSourceId'] field from the authsource, it is not propagated through to the authproc filters or to the user.

So I'm still stuck I guess...

Ben McClure

unread,
Aug 22, 2011, 8:42:13 PM8/22/11
to simple...@googlegroups.com
Oh man... So immediately after my last post I again studied the source of AttributeMap.php as an example, and had another face-palm moment... $state['attributes'] should obviously be $state['Attributes'] if I want to reference the proper key :)

Thanks me! Sorry everyone else!

Ben

Olav Morken

unread,
Sep 5, 2011, 5:19:35 AM9/5/11
to simple...@googlegroups.com

There is a special entry in the $state array (PersistentAuthData). That
entry lists which entries in the $state array should be passed to
authentication processing filters (and also which entries will be
available from $as->getAuthData() on the "SP" side).

E.g. (from modules/saml/www/sp/saml2-acs.php):

$state['saml:sp:IdP'] = $idp;
$state['PersistentAuthData'][] = 'saml:sp:IdP';
$state['saml:sp:NameID'] = $nameId;
$state['PersistentAuthData'][] = 'saml:sp:NameID';


Regards,
Olav Morken
UNINETT / Feide

Olav Morken

unread,
Sep 5, 2011, 5:22:32 AM9/5/11
to simple...@googlegroups.com

Just to clear up what is actually happening here:

First of all, the setAttribute() and setAttributes()-functions are
deprecated. They only work for the "old-style" authentication sources,
where authentication was handled by the IdP redirecting to a web page.

What happens when you return from the authentication source is that the
session information is replaced with the data your authentication
source returns in its state array. Therefore the setAttribute-function
will not work.

Ben McClure

unread,
Sep 5, 2011, 11:28:21 AM9/5/11
to simple...@googlegroups.com
Gotcha; Thanks so much for clearing that up! It makes a lot more sense to me now!
--
Ben


--
You received this message because you are subscribed to the Google Groups "simpleSAMLphp" group.
To post to this group, send email to simple...@googlegroups.com.
To unsubscribe from this group, send email to simplesamlph...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/simplesamlphp?hl=en.


Ben McClure

unread,
Sep 13, 2011, 1:39:49 AM9/13/11
to simple...@googlegroups.com
Olav,

I am setting the following in my authproc filter:

$state['Auth.User'] = $user;
$state['PersistentAuthData'][] = 'Auth.User';

But there is no Auth.User key included when I call getAuthDataArray() on the SP.

Am I missing a step somewhere?
--
Ben

Olav Morken

unread,
Sep 13, 2011, 2:30:41 AM9/13/11
to simple...@googlegroups.com
On Tue, Sep 13, 2011 at 00:39:49 -0500, Ben McClure wrote:
> Olav,
>
> I am setting the following in my authproc filter:
>
> $state['Auth.User'] = $user;
> $state['PersistentAuthData'][] = 'Auth.User';
>
>
> But there is no Auth.User key included when I call getAuthDataArray() on the
> SP.
>
> Am I missing a step somewhere?

The PersistentAuthData was only meant for authentication sources, and
not authentication processing filters, so it will not work.

I must say that I never considered the processing filters on the SP
side when adding "PersistentAuthData". SP processing filters are
invoked a bit differently from IdP processing filters.


Btw.: You should always use your module name as a prefix for any data
that you add to the state array, since that should avoid collisions.

Ben McClure

unread,
Sep 13, 2011, 2:51:50 AM9/13/11
to simple...@googlegroups.com
On second thought, I'm not sure how that could work--multiauth forwards to the selected authentication source, and once that completes authentication is considered finished.

As far as I can tell, I'd need to re-implement every authentication source I wish to support to direct back to my authsource for further processing, in order to complete the entire operation within the authentication source.
--
Ben


On Tue, Sep 13, 2011 at 1:42 AM, Ben McClure <ben.m...@gmail.com> wrote:
My flow is currently like this:

  1. Authentication source is called, which is basically a clone of multiauth
  2. User authenticates, and then returns to idP
  3. Authproc filter queries my user service for an account that has the provided authentication data associated with it
  4. If an account does not exist, it redirects the user to a site to create one (or associate it with an existing one), then the user is returned to the authproc filter
  5. The authproc filter includes the user record with the authentication data
  6. User is sent back to the SP, along with their user record from my user service in the session
I suppose the authproc filter functionality could be moved to the authentication source itself--technically, the user should not be considered authenticated fully until their authentication record is associated with a user account anyway, so it would logically make sense. It's just such a complex operation that it seems to make sense to separate it from the basic authentication which is the first step.
--
Ben



comel

unread,
Sep 13, 2011, 7:40:00 AM9/13/11
to simpleSAMLphp
On Sep 13, 8:51 am, Ben McClure <ben.mccl...@gmail.com> wrote:
> On second thought, I'm not sure how that could work--multiauth forwards to
> the selected authentication source, and once that completes authentication
> is considered finished.
>
> As far as I can tell, I'd need to re-implement every authentication source I
> wish to support to direct back to my authsource for further processing, in
> order to complete the entire operation within the authentication source.

Or you could modify only multiauth, and use some (nasty) workarounds,
e.g. define your own LoginCompletedHandler:

$state['mymulti:OriginalLoginCompletedHandler'] =
$state['LoginCompletedHandler'];
$state['LoginCompletedHandler'] =
'sspmod_mymulti_Auth_Handlers::LoginCompletedHandler';

in sspmod_mymulti_Auth_Handlers::LoginCompletedHandler($state) do your
processing, and on the end run original LoginCompletedHandler:

$func = $state['mymulti:OriginalLoginCompletedHandler'];
assert('is_callable($func)');
call_user_func($func, $state);
assert('FALSE');

Also you could modify multiauth to write selected source in state,
e.g.:

$state[self::SESSION_SOURCE] = $authId;
$state['PersistentAuthData'][] = self::SESSION_SOURCE;

so you know which source is selected in your LoginCompletedHandler().


>
> On Tue, Sep 13, 2011 at 1:42 AM, Ben McClure <ben.mccl...@gmail.com> wrote:
> > My flow is currently like this:
>
> >    1. Authentication source is called, which is basically a clone of
> >    multiauth
> >    2. User authenticates, and then returns to idP
> >    3. Authproc filter queries my user service for an account that has the
> >    provided authentication data associated with it
> >    4. If an account does not exist, it redirects the user to a site to
> >    create one (or associate it with an existing one), then the user is returned
> >    to the authproc filter
> >    5. The authproc filter includes the user record with the authentication
> >    data
> >    6. User is sent back to the SP, along with their user record from my
> >    user service in the session
>
> > I suppose the authproc filter functionality could be moved to the
> > authentication source itself--technically, the user should not be considered
> > authenticated fully until their authentication record is associated with a
> > user account anyway, so it would logically make sense. It's just such a
> > complex operation that it seems to make sense to separate it from the basic
> > authentication which is the first step.
> > --
> > Ben
>

Ben McClure

unread,
Sep 13, 2011, 2:59:07 AM9/13/11
to simple...@googlegroups.com
Oh, and after re-reading your response I wanted to correct one thing--I'm trying to set the PersistentAuthData from the authproc filter on the idP side, not the SP side.

Is it still a no-go?
--
Ben

Ben McClure

unread,
Sep 13, 2011, 2:42:55 AM9/13/11
to simple...@googlegroups.com
My flow is currently like this:

  1. Authentication source is called, which is basically a clone of multiauth
  2. User authenticates, and then returns to idP
  3. Authproc filter queries my user service for an account that has the provided authentication data associated with it
  4. If an account does not exist, it redirects the user to a site to create one (or associate it with an existing one), then the user is returned to the authproc filter
  5. The authproc filter includes the user record with the authentication data
  6. User is sent back to the SP, along with their user record from my user service in the session
I suppose the authproc filter functionality could be moved to the authentication source itself--technically, the user should not be considered authenticated fully until their authentication record is associated with a user account anyway, so it would logically make sense. It's just such a complex operation that it seems to make sense to separate it from the basic authentication which is the first step.
--
Ben


Olav Morken

unread,
Sep 14, 2011, 2:03:00 AM9/14/11
to simple...@googlegroups.com
On Tue, Sep 13, 2011 at 01:59:07 -0500, Ben McClure wrote:
> Oh, and after re-reading your response I wanted to correct one thing--I'm
> trying to set the PersistentAuthData from the authproc filter on the idP
> side, not the SP side.
>
> Is it still a no-go?

In that case it is a no-go, because authproc-filters are executed for
every authentication request the IdP receives. Updating authentication
data does not really make sense in that case.

I assume that your goal is to save some information until the next time
the filter is executed? In that case you may use setData on the session
object, e.g.:

$session = SimpleSAML_Session::getInstance();
$session->setData('yourmodule:somedata', $userID, 'Value that you want to save', SimpleSAML_Session::DATA_TIMEOUT_LOGOUT);

It can later be retrieved with getData():

$value = $session->getData('yourmodule:somedata', $userID);

Ben McClure

unread,
Sep 14, 2011, 2:30:57 AM9/14/11
to simple...@googlegroups.com
Thanks comel and Olav!

My goal actually is to store an array of user information with every authentication request the idP receives.

I have a particular SP which is designed to hold user information and user profiles (where users go to manage their accounts). My idP authenticates users with a public source (such as Facebook, Google, etc), and then queries my Users site for a user record corresponding to that authentication source, forwarding them to create an account if needed.

When the authproc filter has a user record (which works great up until this point), it is supposed to attach the user's full record (an array) to the authentication request that it returns to the SP. The authentication should technically not be considered complete without a user record attached.

My goal for this system was to be able to allow authentication with any defined authsource while still maintaining a single account for each user (no matter how many authsources they use), and being able to attach a user's profile to their account in certain cases.

I've tried every method I can think of to attach the user data to the record, but it just doesn't seem to work--and it sounds like based on your recent responses that it can't work how I'm trying to do it.

Is there a way I can still make this work using an authproc filter, or do I just need to refactor my authsource as per comel's recommendation, so that it all happens right away?
--
Ben


Olav Morken

unread,
Sep 14, 2011, 4:29:02 AM9/14/11
to simple...@googlegroups.com
On Wed, Sep 14, 2011 at 01:30:57 -0500, Ben McClure wrote:
> Thanks comel and Olav!
>
> My goal actually *is* to store an array of user information with every

> authentication request the idP receives.
>
> I have a particular SP which is designed to hold user information and user
> profiles (where users go to manage their accounts). My idP authenticates
> users with a public source (such as Facebook, Google, etc), and then queries
> my Users site for a user record corresponding to that authentication source,
> forwarding them to create an account if needed.
>
> When the authproc filter has a user record (which works great up until this
> point), it is supposed to attach the user's full record (an array) to the
> authentication request that it returns to the SP. The authentication should
> technically not be considered complete without a user record attached.
>
> My goal for this system was to be able to allow authentication with any
> defined authsource while still maintaining a single account for each user
> (no matter how many authsources they use), and being able to attach a user's
> profile to their account in certain cases.
>
> I've tried every method I can think of to attach the user data to the
> record, but it just doesn't seem to work--and it sounds like based on your
> recent responses that it can't work how I'm trying to do it.
>
> Is there a way I can still make this work using an authproc filter, or do I
> just need to refactor my authsource as per comel's recommendation, so that
> it all happens right away?

Ah, you are trying to send data from the IdP to the SP through the
"AuthData" interface? That will not work. The "AuthData" is strictly
internal to the IdP or SP that it runs on.

Data sent from an IdP to an SP is usually transported through
attributes in the assertion that is sent as part of the authentication
response.

To attach an attribute, add it to the 'Attributes' entry in the
filter:

$state['Attributes']['SomeAttribute'] = array(
'SomeValue',
'SomeOtherValue',

Ben McClure

unread,
Sep 14, 2011, 4:54:38 AM9/14/11
to simple...@googlegroups.com
That was the first thing I tried, however it seems to only allow a single-dimensional array.

The user array I need to store is multi-dimensional, with values such as $user['User']['id'], $user['Profile']['phone'], etc.

Is there a way I can pass a multi-dimensional array from the idP to the SP for use in the application?

Thank you,
--
Ben


Olav Morken

unread,
Sep 14, 2011, 6:15:29 AM9/14/11
to simple...@googlegroups.com
On Wed, Sep 14, 2011 at 03:54:38 -0500, Ben McClure wrote:
> That was the first thing I tried, however it seems to only allow a
> single-dimensional array.
>
> The user array I need to store is multi-dimensional, with values such as
> $user['User']['id'], $user['Profile']['phone'], etc.
>
> Is there a way I can pass a multi-dimensional array from the idP to the SP
> for use in the application?

This has to do with the way that attributes are transferred in the
SAML 2.0 standard. By default, an attribute is transmitted as the
following XML:

<saml:Attribute Name="somename" NameFormat="somenameformat">
<saml:AttributeValue xsi:type="xs:string">somevalue</saml:AttributeValue>
<saml:AttributeValue xsi:type="xs:string">someothervalue</saml:AttributeValue>
</saml:Attribute>

To transmitt multidimensional data through standard SAML 2.0 messages,
you will need to define a custom XML format for your data.
Unfortunately, support for this in simpleSAMLphp is incomplete. We
support transmitting custom XML, but not parsing it.

One simple alternative may be to flatten your data structure to a
single associative array:

$state['Attributes']['User:id'] = array( 'userid...' );
$state['Attributes']['Profile:phone'] = array( '+4712345678' );

A different alternative, which may be a bit ugly, would be to use JSON:

$state['Attributes']['user'] = array( json_encode($user) );

Ben McClure

unread,
Sep 14, 2011, 12:40:42 PM9/14/11
to simple...@googlegroups.com
Really great suggestions!

Flattening the array would keep it more readable right off the bat, but I think it would be harder to maintain as models and fields are changed or expanded.

While JSON might be ugly to use in this case, I think you've caught onto a really neat solution for me. I'm already using JSON-based REST services from my Users website to transmit the User data back to the idP, so both services are already prepared to send and receive JSON--it sounds like a solution that might actually work, and quite easily since it only requires me to change a single PHP line on the idP side from how it's set up right now.

Thanks, now I've got anotther avenue to try :) Will follow up with how it is working.
--
Ben


Ben McClure

unread,
Sep 14, 2011, 4:23:55 PM9/14/11
to simple...@googlegroups.com
Hm, so I used json_encode() on the User array and the string is valid JSON, but when I assign it to an attribute in the state array, that attribute comes out on the SP side as en empty array.

Is there some step I'm missing to being able to add a new attribute, other than just assigning it to $state['Attributes']['name']?

--
Ben

Ben McClure

unread,
Sep 14, 2011, 4:28:08 PM9/14/11
to simple...@googlegroups.com
I just forgot to wrap the JSON string in an array like you demonstrated. It works perfectly now, and I have the full user array at all of my SPs now.

Thank you so much for the assistance, and for making this highly extendable and flexible SAML provider.

I'm shocked how simple it turned out to be to get it to do exactly what I want, thanks to the assistance of you and others in this group.
--
Ben
Reply all
Reply to author
Forward
0 new messages