Hey all,
I'm using Tomcat 6.0.14 and would like to know to implement a system that would allow us to send users a link say mysite.com?token=12345678912334333(long string continued) but that would allow the user to be logged in automatically.
Unless you have other reasons specific to Tomcat, or you are unable to modify your web application, then it might be easiest to use a custom filter to do the authentication (JAAS or otherwise). For example:
http://www.kopz.org/public/documents/tomcat/jaasintomcat.html
http://securityfilter.sourceforge.net/
With a custom filter, you could authenticate in whatever way you wanted to in a relatively straightforward way.
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
String token = request.getParameter("token");
if (token != null) {
doAuthentication(token);
}
chain.doFilter(request, wrapper);
}
You tagged with JAAS. That's different than just authenticating with a simple token, but if that's what you are looking for, are you familiar with Tomcat's JAASRealm? You would just have to write your own LoginModule to authenticate the token.
http://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html#JAASRealm
It probably goes without saying that using token based login via E-mail is inherently insecure, and so is not appropriate for all types of applications.
I guess you have to implement the logic by yourself, i.e. the link guide the user to a servlet or something like that which recognize that link, join it with the user, create a session object and redirect the user inside your app.
Hope this helps
Related
I have a regular ASP.Net Core web site that users access using Windows Authentication to determine which users can access which pages.
In order to render a page for the user, the site needs to call in to a series of web services to fetch various bits of data. These web services don't use Windows Authentication. Instead, they require the user's JWT Token.
So, our WebSite needs to exchange the user's Windows token for a JWT token. We have a special ExchangeToken web service that accepts a request using Windows Authentication, and returns the user's JWT Token.
The difficulty comes when I want WebSite to call this ExchangeToken web service. I need to call it using Impersonation, so that I get the user's JWT Token back. However, it doesn't appear to be possible to use HttpClient with Impersonation.
Initially, I had planned to do this in WebSite:
Repeatedly...
Impersonate the user
Instantiate an HttpClient
Call the TokenExchange service to get the JWT Token
Dispose the HttpClient
Stop impersonation
Return the token
However, according to what I've read, re-creating an HTTP client for every call is bad practice, and I should be using HttpClientFactory instead.
However, I don't see how this approach can work with Impersonation.
I tried this:
Use HttpClientFactory to create an HttpClient
Repeatedly...
Impersonate the user
Call the TokenExchange service to get the JWT Token
Stop impersonation
Return the token
However, what happens is that, despite the impersonation, all calls to the TokenExchange service are made with the same windows credentials - the credentials of the user who happens to access the web site first. AFAIK, this stems from the way that Windows Authentication works - it performs a token exchange the first time you use an HttpClient, and from then on, all calls for that client use the same token.
One option would be to create a separate client for each user... but I have about 7,000 users, so that seems a bit excessive!
Another option would be to trust the WebSite to fetch the tokens on behalf of the user, using its own account. The problem with this is that it entails trusting the WebSite. If it is compromised by an attacker, then I can't stop the attacker stealing JWT tokens for arbitrary user. Whereas, with the impersonation, the attacker still can't get a user's JWT token without first obtaining their Windows token.
So, is there a way to do impersonation + IHttpClientFactory together? Or is there a better way to approach all this?
(If it matters, my company has its own Windows servers - we're not in the cloud, yet)
To demonstrate the problem with the second approach, I made a test application. It doesn't actually use HttpClientFactory, but it does demonstrate the problem.
I started with a web site that just returns the user who made a call:
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class WhoController : ControllerBase
{
[HttpGet]
public ActionResult<string> Get()
{
return User.Identity.Name;
}
}
My client code works like this:
private void CallClient(HttpClient httpClient, string username, string password)
{
LogonUser(username, "MYDOMAIN", password, 2, 0, out IntPtr token);
var accessTokenHandle = new SafeAccessTokenHandle(token);
WindowsIdentity.RunImpersonated(
accessTokenHandle,
() =>
{
string result = httpClient.GetStringAsync("http://MyServer/api/who").Result;
Console.WriteLine(result);
});
}
And my test code invokes it like this:
public void Test()
{
var httpClient = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true });
CallClient(httpClient, "User1", "Password1");
CallClient(httpClient, "User2", "Password2");
}
As described above, I get the following written to the console:
User1
User1
What I want is:
User1
User2
TL;DR: NET Core is doing a lot to fight you on this approach under the hood.
Not entirely an answer on what to do, but hopefully helpful background on the HttpClientFactory approach, based on my understanding of the components.
First, from the ASP NET Core docs in regards to impersonation:
ASP.NET Core doesn't implement impersonation. Apps run with the app's
identity for all requests, using app pool or process identity. If the
app should perform an action on behalf of a user, use
WindowsIdentity.RunImpersonated in a terminal inline middleware in
Startup.Configure. Run a single action in this context and then close
the context.
RunImpersonated doesn't support asynchronous operations and shouldn't
be used for complex scenarios. For example, wrapping entire requests
or middleware chains isn't supported or recommended.
As you call out, there's a lot of progress NET Core has made around how HttpClient instances are handled to resolve socket exhaustion and the expensive operations around the underlying handlers. First, there's HttpClientFactory, which in addition to supporting creating named/typed clients with their own pipelines, also attempts to manage and reuse a pool of primary handlers. Second, there's SocketsHttpHandler, which itself manages a connection pool and replaces the previous unmanaged handler by default and is actually used under the hood when you create a new HttpClientHandler. There's a really good post about this on Steve Gordon's Blog: HttpClient Connection Pooling in NET Core. As you're injecting instances of HttpClient around from the factory, it becomes way safer to treat them as scoped and dispose of them because the handlers are no longer your problem.
Unfortunately, all that pooling and async-friendly reuse makes your particular impersonation case difficult, because you actually need the opposite: synchronous calls that clean up after themselves and don't leave the connection open with the previous credentials. Additionally, what used to be a lower-level capability, HttpWebRequest now actually sits on top of HttpClient instead of the other way around, so you can't even skip it all that well by trying to run the requests as a one off. It might be a better option to look into using OpenID Connect and IdentityServer or something to centralize that identity management and Windows auth and pass around JWT everywhere instead.
If you really need to just "make it work", you might try at least adding some protections around the handler and its connection pooling when it comes to the instance that is getting used to make these requests; event if the new clients per request are working most of the time, deliberately cleaning up after them might be safer. Full disclaimer, I have not tested the below code, so consider it conceptual at best.
(Updated Switched the static/semaphore to a regular instance since the last attempt didn't work)
using (var handler = new SocketsHttpHandler() { Credentials = CredentialCache.DefaultCredentials, PooledConnectionLifetime = TimeSpan.Zero, MaxConnectionsPerServer = 1 })
using (var client = new HttpClient(handler, true))
{
return client.GetStringAsync(uri).Result;
}
I need to access the user's password in a Jetty application after authentication, and can't figure out how.
I am migrating a set of web pages away from basic authentication in an embedded Jetty servlet application. I cannot, however, completely remove basic authentication from all of the services that these pages call, so I need to forward the user credentials in some cases, which means storing and later retrieving the user's password.
I introduced forms authentication to the root context via the standard markup in web.xml, which works fine but I can find no way of getting the user credentials programatically. As far as I can tell there is no way to place a Filter on j_security_check to intercept and store the form parameters in the session state. Jetty provides all the user credentials in the session state but this is in a container-specific key and although the application is currently tied to Jetty I would strongly prefer a container-agnostic solution. Here are some specific questions that I've tried to formulate after going down a number of seemingly dead-end streets:
How can I obtain the user's password after login? Even if I moved the services away from basic authentication I would still need to perform some secondary action such as obtaining a token, in which case I would still need their credentials under my control for a brief period.
Assuming I can't obtain the user's password directly, perhaps I can leverage something in the container to store the credentials. I can implement my own LoginService that wraps the actual implementation, but that class does not have access to the HttpSession or Request objects. Where is the proper place to do this?
If I need to implement a custom login solution, I'm not quite sure where to start...the FormAuthenticator has a lot of complicated session state management that I would like to preserve and not reproduce willy-nilly, and I would still prefer to defer to the container standard as much as possible. Is there some standard method for extending or overriding the j_security_check logic?
I finally found one solution, for anyone else attempting similar - and I've found quite a few other posts from confused devs, and some badly hacked together workarounds. I believe this one is correct, although you must do the URL filtering yourself and it leaves open the question as to why this is possible, if indeed j_security_check should be exempt from this type of interception for security reasons, as is claimed many places online. Perhaps I am merely exploiting an unknown gap in the Jetty security measures, so I will leave this question open for a while to see if there is a more robust or explicit solution.
ServletRequestListener allows you to latch onto the j_security_check post request before it is fully initialized. There you can get both the form parameters and the session object. So in the end it was just a matter of exhausting every possible servlet-related class in Jetty until I found one that would give me access to the j_security_check request. Some code:
public class PreAuthenticationRequestListener implements ServletRequestListener {
public static final String USERNAME_KEY = "USERNAME";
public static final String PASSWORD_KEY = "PASSWORD";
#Override
public void requestDestroyed(ServletRequestEvent sre) {
}
#Override
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
if (request.getRequestURI().contains("j_security_check")) {
final String username = request.getParameter("j_username");
final String password = request.getParameter("j_password");
HttpSession session = request.getSession();
session.setAttribute(USERNAME_KEY, username);
session.setAttribute(PASSWORD_KEY, password);
}
}
}
I started working on Web Api and just want to create a simple basic authentication. I want to know how to do that?
I tried with the given MSDN link but no step wise tutorial is given on MSDN.
http://www.asp.net/web-api/overview/security/basic-authentication
The link you gave provides much of the detail you need, I hope this fills in the blanks.
Note: If using Web.API 2, Microsoft are suggesting a different approach using authentication filters.
Set up https on your server
This is quite important if you need real security otherwise passwords can be gleaned by snooping parties. How you do this depends a entirely on your setup, which you don't detail, but if you're working on an Azure WebRole there's a pretty good step-by-step guide to setting up SSL from Microsoft.
This isn’t required for the next steps, but should be done before you release your code. I mention it first because this part usually involves getting other people involved (sysadmin for server config, finance to purchase the certificate, etc) and it’s good to give them lots of warning.
Write (or steal) a custom IHttpModule to do your authentication
This is the big block of C# code in your link - it parses the values sent by the browser and sets HttpContext.Current.User to the authenticated user. Just copy and paste the meat into a class in your own application and we’ll come back to it later. You’ll need the following using statements in your code.
using System; using System.Net.Http.Headers; using System.Security.Principal;
using System.Text; using System.Threading; using System.Web;
Associate that module with your application
Add a new module to your web.config file (note system.webServer probably already exists)
<system.webServer>
<modules>
<add name="BasicAuth" type="Full.ClassName.Path.BasicAuth, Assembly.Name"/>
</modules>
</system.webServer>
Restrict access to the relevant parts of your site
You can block specific actions by adding the [Authorize] attribute before the action definition. Block a whole controller by adding it before your controller class.
[Authorize] // Restricts access to whole controller
public class StockController : ApiController {
[Authorize] // Restricts access to this action - not necessary if whole controller restricted.
public IEnumerable<StockLevel> Get() {
Or in your App_Start\WebApiConfig.cs file you can add config.Filters.Add(new AuthorizeAttribute()); and it will lock everything down.
Something to watch out for - there’s also a System.Web.Mvc.AuthorizeAttribute so if you have that namespace included you can get confusing results.
At this point you can try it out - user: "user", pass: "password".
Customize your user validation
Go back to the class we stole from the link and you'll see the following block of code:
// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)
Alter this to return true if the username and password are valid. If you're rolling your own you may want to investigate bcrypt (do you trust the implementation you downloaded off the net?), PBKDF2 or the Crypto class (simple but not terribly secure) but there's probably something better from Microsoft as there are lot of concerns around storing passwords properly.
I had to add a few lines of code to the MSDN example to get it to work. Specifically, in OnApplicationAuthenticateRequest(), I set the response status code to 401 if the user could not be validated:
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
bool validated = false;
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("basic",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
validated = AuthenticateUser(authHeaderVal.Parameter);
}
}
if (!validated)
{
HttpContext.Current.Response.StatusCode = 401;
}
}
Once I did that, it worked fine. There's probably better ways to structure the logic, but this is about the smallest change from the example that does the job.
To selectively enable basic authentication on a per-controller or per-method basis, you can derive from AuthorizeAttribute as described in this question.
i am new in wcf so one question bugging me like wcf and user authentication. generally in asp.net i send user name and password and at the server end it is validated against database and if user is valid then i store some data in session and in every page i check the session and if the session exist and true is stored for that user in that session then i let the page execute otherwise i redirect user to login page. so i want to know how to implement this kind of user authentication in wcf. i want when first time user will call any method of my service then he will pass credential and if credential is fine then he can call any method of my service. please guide me how could i do it in wcf. in wcf how i can store any data in session for each user who will call my service....is there any way??
i search google and found one like http://blog.adnanmasood.com/2010/04/29/step-by-step-guide-for-authenticating-wcf-service-with-username-and-password-over-ssl/
but here anyone notice caller pass user name & password but code look like user name and password comes twice like
private static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(
delegate { return true; });
var client = new WcfServiceClient();
GetCredentials();
client.ClientCredentials.UserName.UserName = username;
client.ClientCredentials.UserName.Password = password;
Console.Write(client.GetData(1));
client.Close();
Console.Read();
}
...but why two user name and password is coming UserName.UserName it looks very ugly.
give me the best idea how to authenticate users against DB when they first time call my service and once authenticated then from the next time he can call any method of my service without giving credentials.
some one told me to develop service for authenticate user.once user authenticate then service will provide some unique token id to each wcf client and client will pass that token as message header when call any method......i have no idea how to implement it and even i do not know would it be best or not. so looking for guidance and suggestion. thanks
The most common way of dealing with WCF authentication is to have the client program ask for username and password once (or retrieve it from a config file), and have the client program provide it for every service call. Some examples can be found at http://msdn.microsoft.com/en-us/library/ff405740.aspx.
The alternative is to have user sessions, which are generally a bad idea. Sessions do not scale easily, there are client and server platform compatibility considerations etc...
I'm trying to integrate Spring Security in my web application. It seems pretty easy to do as long as you integrate the whole process of authentication and authorization.
However, both authentication and authorization seem so coupled that it's being very time-consuming for me to understand how I could split these processes, and get authentication independently of authorization.
The authentication process is external to our system (based on single sign-on) and this cannot be modified. Nevertheless, once the user succeeds this process, it's loaded in the session, including roles.
What we are trying to achieve is to make use of this information for the authorization process of Spring Security, that's to say, to force it to get the roles from the user session instead of picking it up through the authentication-provider.
Is there any way to achieve this?
If your authentication is already done using an SSO service, then you should use one of spring security's pre-authentication filters. Then you can specify a UserDetails service (possibly custom) that will use the pre-authenticated user principle to populate the GrantedAuthority's
SpringSecurity includes several pre-authentication filters including J2eePreAuthenticatedProcessingFilter and RequestHeaderPreAuthenticatedProcessingFilter. If you can't find one that works for you, its also possible, and not that hard to write your own, provided you know where in the request your SSO implementation stuffs the data. (That depends on the implementation of course.)
Just implement the Filter interface and do something like this in the doFilter method:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// principal is set in here as a header or parameter. you need to find out
// what it's named to extract it
HttpServletRequest req = (HttpServletRequest) request;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
// in here, get your principal, and populate the auth object with
// the right authorities
Authentication auth = doAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
Yes, it's possible. Spring Security (like most of the rest of Spring) is interface-driven so that you can plug in your own implementations selectively for different parts of the framework.
Update: Spring's authorisation and authentication mechanisms work together - the authentication mechanism will authenticate the user and insert various GrantedAuthority instances in the security context. These will then be checked by the authorisation machinery to allow/disallow certain operations.
Use nont's answer for the details on how to use pre-existing authentication. The details of how you get the details from your session (e.g. roles ) will of course depend on your specific setup. But if you put in the GrantedAuthority instances derived from the roles pre-populated in your session by your SSO system, you will be able to use them in your authorisation logic.
From the reference documentation (slightly edited, with my emphasis):
You can (and many users do) write
their own filters or MVC controllers
to provide interoperability with
authentication systems that are not
based on Spring Security. For example,
you might be using Container Managed
Authentication which makes the current
user available from a ThreadLocal or
JNDI location. Or you might work for a
company that has a legacy proprietary
authentication system, which is a
corporate "standard" over which you
have little control. In such
situations it's quite easy to get
Spring Security to work, and still
provide authorization capabilities.
All you need to do is write a filter
(or equivalent) that reads the
third-party user information from a
location, build an Spring
Security-specific Authentication
object, and put it onto the
SecurityContextHolder. It's quite easy
to do this, and it is a
fully-supported integration approach.
The server that handles the authentication should redirect the user to the application passing to it some kind of key (a token in CAS SSO). Then the application use the key to ask to the authentication server the username and roles associated. With this info create a security context that is passed to the authorization manager. This is a very simplified version of a SSO login workflow.
Take a look to CAS SSO and CAS 2 Architecture.
Tell me if you need more information.
we have had the same requirement where we had to use spring security for authorization purpose only. We were using Siteminder for authentication. You can find more details on how to use authorization part of spring security not authentication here at http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/
I have also added source code and test cases at http://code.google.com/p/spring-security-with-authorization-only/source/browse/
I am trying to understand CAS authentication with our own Authorization and was getting confused since the User object in Spring Security always expects the password to be filled in and we don't care about that in our scenario. After reading Surabh's post, it seems that the trick is to return a custom User object without the password filled in. I will try that out and see if it works in my case. Hopefully no other code in the chain will be expecting the Password in the User object.
I use the authorization by this:
Inject the authorization related bean into my own bean:
#Autowired
private AccessDecisionManager accessDecisionManager;
#Autowired
FilterSecurityInterceptor filterSecurityInterceptor;
Use this bean by this:
FilterInvocation fi = new FilterInvocation(rundata.getRequest(), rundata.getResponse(), new FilterChain() {
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException {
// TODO Auto-generated method stub
}
});
FilterInvocationDefinitionSource objectDefinitionSource = filterSecurityInterceptor.getObjectDefinitionSource();
ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(fi);
Authentication authenticated = new Authentication() {
...........
public GrantedAuthority[] getAuthorities() {
GrantedAuthority[] result = new GrantedAuthority[1];
result[0] = new GrantedAuthorityImpl("ROLE_USER");
return result;
}
};
accessDecisionManager.decide(authenticated, fi, attr);
I too did spent lot of hours investigating on how to implement custom authorization without authentication.
The authentication process is external to our system (based on single sign-on).
I have done it, as mentioned below and it Works!!! (I am sure there are many other ways to it better, but this way just suits my scenario well enough)
Scenario : User is already authenticated by external system and all information needed for authorization is present in the request
1.
Security config need to be created, enabling global method security as below.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
class SpringWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
}
}
2.) Implement Spring PermissionEvaluator to authorize whether the request should be allowed or rejected
#Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean authorize(final String groups, final String role) {
boolean allowed = false;
System.out.println("Authorizing: " + groups + "...");
if (groups.contains(role)) {
allowed = true;
System.out.println(" authorized!");
}
return allowed;
};
#Override
public boolean hasPermission(final Authentication authentication, final Object groups, final Object role) {
return authorize((String) groups, (String) role);
};
#Override
public boolean hasPermission(final Authentication authentication, final Serializable targetId, final String targetType, final Object permission) {
return authorize((String) targetId, (String) permission);
};
}
3.) Add MethodSecurityConfig
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}
4.) Add #PreAuthorize in your controller as shown below. In this example, all the groups of the user are present in request header with key 'availableUserGroups'.
This is then passed on to the CustomPermissionEvaluator to verify authorization. Please note that spring automatically passes Authentication object to the method 'hasPermission'.
So in case if you want to load user and check using spring 'hasRole' method, then this can be used.
#PreAuthorize("hasPermission(#userGroups, 'ADMIN')")
#RequestMapping(value = "/getSomething")
public String getSomething(#RequestHeader(name = "availableUserGroups") final String userGroups) {
return "resource allowed to access";
}
Handling Other Scenarios :
1.) In scenario where you want to load the user before you can perform the authorization. You can use spring pre-authentication filters, and do it in a similar way.
Example link : http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html