By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,077 Members | 1,175 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,077 IT Pros & Developers. It's quick & easy.

Using PrincipalPermission on WebMethods with Forms Authentication

P: n/a
Greetings:

I am developing an application that uses an ASP.NET Web Forms
application for its UI and ASP.NET web services for its business tier, and I
am looking for assistance in improving my application security. I want to use
declarative security on my web methods so I can secure them more easily. In
short, I want to secure the web services using the first code snippet below.

Please note that the web method has a custom SOAP header. This header
includes three properties, username, password and client id, and currently
provides the mechanism for securing web service access. Each web method
contains code to check the values from the SOAP header against the
application's security metadata. Because of the nature of the application I
cannot use Active Directory - user's must be validated against a database,
and the client id values determines against what database the user name and
password will be validated. I am hoping to avoid the use of procedural code
and to use the PrincipalPermission attribute on my web methods to restrict
access, like so:

[SoapHeader("authHeader")]
[PrincipalPermission(SecurityAction.Demand, Role = "RoleName")]
public DataSet GetUserDetails(...paramlist...)
{
//...
}

This works great, in that the PrincipalPermission attribute is checking
for the specified role, and denying access to the web method. Sadly, it does
this for all users, even those that are members of the appropriate roles - I
cannot figure out how to actually pass a user's credentials along to the web
method from the ASP.NET web forms client application in a manner so that this
actually works. Based on any number of suggestions online, I've tried this in
my client code, to no avail:

UserAdminWS.UserAdmin wsProxy = new UserAdmin();
wsProxy.AuthenticationHeaderValue = new UserAdminWS.AuthenticationHeader();
wsProxy.PreAuthenticate = true;

wsProxy.AuthenticationHeaderValue.clientID = clientID;
wsProxy.AuthenticationHeaderValue.userName = userName;
wsProxy.AuthenticationHeaderValue.userPassword = userPassword;

System.Net.CredentialCache credCache = new System.Net.CredentialCache();
credCache.Add (new Uri(wsProxy.Url), "Basic", new
System.Net.NetworkCredential(wsProxy.Authenticatio nHeaderValue.userName,
wsProxy.AuthenticationHeaderValue.userPassword,
wsProxy.AuthenticationHeaderValue.clientID));

wsProxy.Credentials = credCache;

As far as I can tell, this should work, or at least should be a big part
of the solution, but when I interrogate
HttpContext.Current.User.Identity.Name it always contains the empty string,
and HttpContext.Current.User.Identity.IsAuthenticated is always false. WTF?

I have also tried using the sample code from
http://www.rassoc.com/gregr/weblog/s...Directory.html
and
http://www.rassoc.com/gregr/weblog/s...Directory.html,
but neither one supports passing a third value along with the user name and
password, and without the ability to use the client id any solution is
useless to me.

I'm sure I'm missing something painfully simple, but can't guess what
that might be. Any thoughts or suggestions would be greatly appreciated.
Thanks in advance!

Matthew Roche

Nov 21 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Hi Matthew,

Are you setting the current user identity in the web service? To do this,
you need to create a Principal object and assign it to the
System.Threading.Thread.CurrentPrincipal property after successful
authentication.

Moreover, I think it is unnecessary to pass the credentials through both a
SoapHeader and proxy.Credentials. If you want to use the SoapHeader, then
write a SoapExtension to examine the header, check the credentials and upon
successful authentication, set the current user identity. Alternatively, if
you want to use HTTP Basic or Digest authentication, pass the credentials in
proxy.Credentials, validate the credentials in the HttpModule (similarly to
Reinacker's sample) and set the current user identity. With one of these in
place, you should be able to use declarative security with the
PrincipalPermission attribute.

Regards,
Sami

"Matthew Roche" <fi****************************@online.nospam> wrote in
message news:F5**********************************@microsof t.com...
Greetings:

I am developing an application that uses an ASP.NET Web Forms
application for its UI and ASP.NET web services for its business tier, and
I
am looking for assistance in improving my application security. I want to
use
declarative security on my web methods so I can secure them more easily.
In
short, I want to secure the web services using the first code snippet
below.

Please note that the web method has a custom SOAP header. This header
includes three properties, username, password and client id, and currently
provides the mechanism for securing web service access. Each web method
contains code to check the values from the SOAP header against the
application's security metadata. Because of the nature of the application
I
cannot use Active Directory - user's must be validated against a database,
and the client id values determines against what database the user name
and
password will be validated. I am hoping to avoid the use of procedural
code
and to use the PrincipalPermission attribute on my web methods to restrict
access, like so:

[SoapHeader("authHeader")]
[PrincipalPermission(SecurityAction.Demand, Role = "RoleName")]
public DataSet GetUserDetails(...paramlist...)
{
//...
}

This works great, in that the PrincipalPermission attribute is checking
for the specified role, and denying access to the web method. Sadly, it
does
this for all users, even those that are members of the appropriate roles -
I
cannot figure out how to actually pass a user's credentials along to the
web
method from the ASP.NET web forms client application in a manner so that
this
actually works. Based on any number of suggestions online, I've tried this
in
my client code, to no avail:

UserAdminWS.UserAdmin wsProxy = new UserAdmin();
wsProxy.AuthenticationHeaderValue = new
UserAdminWS.AuthenticationHeader();
wsProxy.PreAuthenticate = true;

wsProxy.AuthenticationHeaderValue.clientID = clientID;
wsProxy.AuthenticationHeaderValue.userName = userName;
wsProxy.AuthenticationHeaderValue.userPassword = userPassword;

System.Net.CredentialCache credCache = new System.Net.CredentialCache();
credCache.Add (new Uri(wsProxy.Url), "Basic", new
System.Net.NetworkCredential(wsProxy.Authenticatio nHeaderValue.userName,
wsProxy.AuthenticationHeaderValue.userPassword,
wsProxy.AuthenticationHeaderValue.clientID));

wsProxy.Credentials = credCache;

As far as I can tell, this should work, or at least should be a big
part
of the solution, but when I interrogate
HttpContext.Current.User.Identity.Name it always contains the empty
string,
and HttpContext.Current.User.Identity.IsAuthenticated is always false.
WTF?

I have also tried using the sample code from
http://www.rassoc.com/gregr/weblog/s...Directory.html
and
http://www.rassoc.com/gregr/weblog/s...Directory.html,
but neither one supports passing a third value along with the user name
and
password, and without the ability to use the client id any solution is
useless to me.

I'm sure I'm missing something painfully simple, but can't guess what
that might be. Any thoughts or suggestions would be greatly appreciated.
Thanks in advance!

Matthew Roche


Nov 21 '05 #2

P: n/a
Sami:

Thanks for the reply. I guess I wasn't as clear as I was trying to be in
explaining my context. I'm actually trying to find a way to use either one or
the other method for validating users. The SOAP header is my current working
solution, but I haven't been able to make it work with the
PrincipalPermission attribute. I agree that both techniques are not
necessary, but as I haven't yet been able to get either one to work I wanted
to keep my bases covered.

To answer your question "Are you setting the current user identity in
the web service?" the answer currently is No. I honestly am unsure *where* to
set it. So far my web services work has been pretty straightforward, and I
haven't had cause until now to drill down into this sort of thing. I will
take a look at creating a SoapExtension as you suggested and will post a
reply when I have something to report.

Thanks again!

Matthew

"Sami Vaaraniemi" wrote:
Hi Matthew,

Are you setting the current user identity in the web service? To do this,
you need to create a Principal object and assign it to the
System.Threading.Thread.CurrentPrincipal property after successful
authentication.

Moreover, I think it is unnecessary to pass the credentials through both a
SoapHeader and proxy.Credentials. If you want to use the SoapHeader, then
write a SoapExtension to examine the header, check the credentials and upon
successful authentication, set the current user identity. Alternatively, if
you want to use HTTP Basic or Digest authentication, pass the credentials in
proxy.Credentials, validate the credentials in the HttpModule (similarly to
Reinacker's sample) and set the current user identity. With one of these in
place, you should be able to use declarative security with the
PrincipalPermission attribute.

Regards,
Sami

"Matthew Roche" <fi****************************@online.nospam> wrote in
message news:F5**********************************@microsof t.com...
Greetings:

I am developing an application that uses an ASP.NET Web Forms
application for its UI and ASP.NET web services for its business tier, and
I
am looking for assistance in improving my application security. I want to
use
declarative security on my web methods so I can secure them more easily.
In
short, I want to secure the web services using the first code snippet
below.

Please note that the web method has a custom SOAP header. This header
includes three properties, username, password and client id, and currently
provides the mechanism for securing web service access. Each web method
contains code to check the values from the SOAP header against the
application's security metadata. Because of the nature of the application
I
cannot use Active Directory - user's must be validated against a database,
and the client id values determines against what database the user name
and
password will be validated. I am hoping to avoid the use of procedural
code
and to use the PrincipalPermission attribute on my web methods to restrict
access, like so:

[SoapHeader("authHeader")]
[PrincipalPermission(SecurityAction.Demand, Role = "RoleName")]
public DataSet GetUserDetails(...paramlist...)
{
//...
}

This works great, in that the PrincipalPermission attribute is checking
for the specified role, and denying access to the web method. Sadly, it
does
this for all users, even those that are members of the appropriate roles -
I
cannot figure out how to actually pass a user's credentials along to the
web
method from the ASP.NET web forms client application in a manner so that
this
actually works. Based on any number of suggestions online, I've tried this
in
my client code, to no avail:

UserAdminWS.UserAdmin wsProxy = new UserAdmin();
wsProxy.AuthenticationHeaderValue = new
UserAdminWS.AuthenticationHeader();
wsProxy.PreAuthenticate = true;

wsProxy.AuthenticationHeaderValue.clientID = clientID;
wsProxy.AuthenticationHeaderValue.userName = userName;
wsProxy.AuthenticationHeaderValue.userPassword = userPassword;

System.Net.CredentialCache credCache = new System.Net.CredentialCache();
credCache.Add (new Uri(wsProxy.Url), "Basic", new
System.Net.NetworkCredential(wsProxy.Authenticatio nHeaderValue.userName,
wsProxy.AuthenticationHeaderValue.userPassword,
wsProxy.AuthenticationHeaderValue.clientID));

wsProxy.Credentials = credCache;

As far as I can tell, this should work, or at least should be a big
part
of the solution, but when I interrogate
HttpContext.Current.User.Identity.Name it always contains the empty
string,
and HttpContext.Current.User.Identity.IsAuthenticated is always false.
WTF?

I have also tried using the sample code from
http://www.rassoc.com/gregr/weblog/s...Directory.html
and
http://www.rassoc.com/gregr/weblog/s...Directory.html,
but neither one supports passing a third value along with the user name
and
password, and without the ability to use the client id any solution is
useless to me.

I'm sure I'm missing something painfully simple, but can't guess what
that might be. Any thoughts or suggestions would be greatly appreciated.
Thanks in advance!

Matthew Roche


Nov 21 '05 #3

P: n/a
Sami:

Yes, that did the trick. Here's what I did:

1) I created a custom SoapExtension class that calls into my application
database to validate the user's credentials using the values from the SOAP
header and build GenericIdentity and GenericPrincipal and assign the
principal to the current HTTP context and the current thread (the thread
hookup was necessary for the PrincipalPermission attribute to work - setting
the context identity was not sufficient)
2) I created a custom SoapExtensionAttribute class with which to tie the
SoapExtension to the web methods I needed to secure
3) I tagged each web method with the custom SoapExtensionAttribute and
the PrincipalPermission attribute

And now everything works. Thanks for your help!

Matthew

"Sami Vaaraniemi" wrote:
Hi Matthew,

Are you setting the current user identity in the web service? To do this,
you need to create a Principal object and assign it to the
System.Threading.Thread.CurrentPrincipal property after successful
authentication.

Moreover, I think it is unnecessary to pass the credentials through both a
SoapHeader and proxy.Credentials. If you want to use the SoapHeader, then
write a SoapExtension to examine the header, check the credentials and upon
successful authentication, set the current user identity. Alternatively, if
you want to use HTTP Basic or Digest authentication, pass the credentials in
proxy.Credentials, validate the credentials in the HttpModule (similarly to
Reinacker's sample) and set the current user identity. With one of these in
place, you should be able to use declarative security with the
PrincipalPermission attribute.

Regards,
Sami

"Matthew Roche" <fi****************************@online.nospam> wrote in
message news:F5**********************************@microsof t.com...
Greetings:

I am developing an application that uses an ASP.NET Web Forms
application for its UI and ASP.NET web services for its business tier, and
I
am looking for assistance in improving my application security. I want to
use
declarative security on my web methods so I can secure them more easily.
In
short, I want to secure the web services using the first code snippet
below.

Please note that the web method has a custom SOAP header. This header
includes three properties, username, password and client id, and currently
provides the mechanism for securing web service access. Each web method
contains code to check the values from the SOAP header against the
application's security metadata. Because of the nature of the application
I
cannot use Active Directory - user's must be validated against a database,
and the client id values determines against what database the user name
and
password will be validated. I am hoping to avoid the use of procedural
code
and to use the PrincipalPermission attribute on my web methods to restrict
access, like so:

[SoapHeader("authHeader")]
[PrincipalPermission(SecurityAction.Demand, Role = "RoleName")]
public DataSet GetUserDetails(...paramlist...)
{
//...
}

This works great, in that the PrincipalPermission attribute is checking
for the specified role, and denying access to the web method. Sadly, it
does
this for all users, even those that are members of the appropriate roles -
I
cannot figure out how to actually pass a user's credentials along to the
web
method from the ASP.NET web forms client application in a manner so that
this
actually works. Based on any number of suggestions online, I've tried this
in
my client code, to no avail:

UserAdminWS.UserAdmin wsProxy = new UserAdmin();
wsProxy.AuthenticationHeaderValue = new
UserAdminWS.AuthenticationHeader();
wsProxy.PreAuthenticate = true;

wsProxy.AuthenticationHeaderValue.clientID = clientID;
wsProxy.AuthenticationHeaderValue.userName = userName;
wsProxy.AuthenticationHeaderValue.userPassword = userPassword;

System.Net.CredentialCache credCache = new System.Net.CredentialCache();
credCache.Add (new Uri(wsProxy.Url), "Basic", new
System.Net.NetworkCredential(wsProxy.Authenticatio nHeaderValue.userName,
wsProxy.AuthenticationHeaderValue.userPassword,
wsProxy.AuthenticationHeaderValue.clientID));

wsProxy.Credentials = credCache;

As far as I can tell, this should work, or at least should be a big
part
of the solution, but when I interrogate
HttpContext.Current.User.Identity.Name it always contains the empty
string,
and HttpContext.Current.User.Identity.IsAuthenticated is always false.
WTF?

I have also tried using the sample code from
http://www.rassoc.com/gregr/weblog/s...Directory.html
and
http://www.rassoc.com/gregr/weblog/s...Directory.html,
but neither one supports passing a third value along with the user name
and
password, and without the ability to use the client id any solution is
useless to me.

I'm sure I'm missing something painfully simple, but can't guess what
that might be. Any thoughts or suggestions would be greatly appreciated.
Thanks in advance!

Matthew Roche


Nov 21 '05 #4

P: n/a

"Matthew Roche" <fi****************************@online.nospam> wrote in
message news:6E**********************************@microsof t.com...
Sami:

Yes, that did the trick. Here's what I did:

1) I created a custom SoapExtension class that calls into my
application
database to validate the user's credentials using the values from the SOAP
header and build GenericIdentity and GenericPrincipal and assign the
principal to the current HTTP context and the current thread (the thread
hookup was necessary for the PrincipalPermission attribute to work -
setting
the context identity was not sufficient)
2) I created a custom SoapExtensionAttribute class with which to tie
the
SoapExtension to the web methods I needed to secure
3) I tagged each web method with the custom SoapExtensionAttribute and
the PrincipalPermission attribute

And now everything works. Thanks for your help!


This was exactly what I meant, glad you figured it out. Note that you can
also attach the SoapExtension attribute to the web service class. This is
convenient if you want the extension to apply to all web methods.

Regards,
Sami

Nov 21 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.