I am using wicket 1.4.7 + spring 3.0 + spring security 3.0
Problem is : Spring security authenticate the user via cookie (remember-me service) but Wicket's AuthenticatedWebSession couldn't understand this and populate login panel. How can i solve it ?
Thanks.
Pretty old question, but I just stumbled upon it while research the exact same problem. So if anybody else comes across this, here's my solution.
The problem is that AuthenticatedWebSession#isSignedIn() ignores the SecurityContext and checks it's own boolean flag instead. As it isn't possible to override the final method #isSignedIn(), there has to be a workaround. I've gone for a custom WebRequestCycle overriding #onBeginRequest() to synchronize state just before Wicket starts processing the current request:
// MyApplication.java
public MyApplication extends AuthenticatedWebApplication {
// SNIP
#Override
public RequestCycle newRequestCycle(final Request request, final Response response) {
return new WebRequestCycle(this, (WebRequest) request, (WebResponse) response) {
#Override
protected void onBeginRequest() {
MySession.get().updateSignIn();
}
};
}
}
// MySession.java
public class MySession extends AuthenticatedWebSession {
// SNIP
void updateSignIn() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
signIn(auth != null && auth.isAuthenticated());
}
}
Alternatively, AuthenticatedWebSession and AuthenticatedWebApplication could be abandoned alltogether as the rest of wicket-auth-roles doesn't require them. It just takes some code duplication from AuthenticatedWebApplication to make everything work similarly.
Related
I am toying with Swashbuckle.Examples package (3.10.0) in an ASP.NET MVC project. However, I cannot make request examples appear within the UI.
Configuration (SwaggerConfig.cs)
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c => {
c.SingleApiVersion("v1", "TestApp.Web");
c.IncludeXmlComments(string.Format(#"{0}\bin\TestApp.Web.xml", System.AppDomain.CurrentDomain.BaseDirectory));
c.OperationFilter<ExamplesOperationFilter>();
c.OperationFilter<DescriptionOperationFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
})
.EnableSwaggerUi(c => { });
}
Request example classes
public class EchoRequestExample : IExamplesProvider
{
public object GetExamples()
{
return new EchoInput { Value = 7 } ;
}
}
public class EchoInput
{
public int Value { get; set; }
}
Action
[HttpGet]
[Route("Echo")]
[CustomApiAuthorize]
[SwaggerRequestExample(typeof(EchoInput), typeof(EchoRequestExample))]
[ResponseType(typeof(EchoServiceModel))]
public HttpResponseMessage Echo([FromUri] EchoInput model)
{
var ret = new EchoServiceModel
{
Username = RequestContext.Principal.Identity.Name,
Value = value
};
return Request.CreateResponse(HttpStatusCode.OK, ret);
}
Swagger UI shows xml comments and output metadata (model and an example containing default values), but shows no request example. I attached to process and EchoRequestExample.GetExamples is not hit.
Question: How to make SwaggerRequestExample attribute work in ASP.NET MVC 5?
Note: Windows identity is used for authorization.
I received an answer from library owner here:
Swagger request examples can only set on [HttpPost] actions
It is not clear if this is a design choice or just a limitation, as I find [HttpGet] examples also relevant.
I know the feeling, lot's of overhead just for an example, I struggle with this for a while, so I created my own fork of swashbuckle, and after unsuccessful attempts to merge my ideas I ended up detaching and renaming my project and pushed to nuget, here it is: Swagger-Net
An example like that will be:
[SwaggerExample("id", "123456")]
public IHttpActionResult GetById(int id)
{
Here the full code for that: Swagger_Test/Controllers/IHttpActionResultController.cs#L26
Wondering how that looks like on the Swagger-UI, here it is:
http://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=IHttpActionResult#/IHttpActionResult/IHttpActionResult_GetById
We have an Azure web role deployed that has been using Application Insights (ver. 1.0.0.4220), however, we're going over our data quota. Is it possible to configure Application Insights ignore a specific URL?
We have a status web service that gets a huge amount of traffic but never throws any errors. If I could exclude this one service URL I could cut my data usage in half.
Out of the box it is not supported. Sampling feature is coming but that would not be configurable by specific url. You can implement your own channel that would have your custom filtering. Basically your channel will get event to be sent, you check if you want to send it or not and then if yes pass to standard AI channel. Here you can read more about custom channels.
There are two things that changed since this blog post has been written:
channel should implement only ITelemetryChannel interface (ISupportConfiguration was removed)
and instead of PersistenceChannel you should use Microsoft.ApplicationInsights.Extensibility.Web.TelemetryChannel
UPDATE: Latest version has filtering support: https://azure.microsoft.com/en-us/blog/request-filtering-in-application-insights-with-telemetry-processor/
My team had a similiar situation where we needed to filter out urls that were successful image requests (we had a lot of these which made us hit the 30k datapoints/min limit).
We ended up using a modified version of the class in Sergey Kanzhelevs blog post to filter these out.
We created a RequestFilterChannel class which is an instance of ServerTelemetryChannel and extended the Send method. In this method we test each telemetry item to be sent to see if it is an image request and if so, we prevent it from being sent.
public class RequestFilterChannel : ITelemetryChannel, ITelemetryModule
{
private ServerTelemetryChannel channel;
public RequestFilterChannel()
{
this.channel = new ServerTelemetryChannel();
}
public void Initialize(TelemetryConfiguration configuration)
{
this.channel.Initialize(configuration);
}
public void Send(ITelemetry item)
{
if (item is RequestTelemetry)
{
var requestTelemetry = (RequestTelemetry) item;
if (requestTelemetry.Success && isImageRequest((RequestTelemetry) item))
{
// do nothing
}
else
{
this.channel.Send(item);
}
}
else
{
this.channel.Send(item);
}
}
public bool? DeveloperMode
{
get { return this.channel.DeveloperMode; }
set { this.channel.DeveloperMode = value; }
}
public string EndpointAddress
{
get { return this.channel.EndpointAddress; }
set { this.channel.EndpointAddress = value; }
}
public void Flush()
{
this.channel.Flush();
}
public void Dispose()
{
this.channel.Dispose();
}
private bool IsImageRequest(RequestTelemetry request)
{
if (request.Url.AbsolutePath.StartsWith("/image.axd"))
{
return true;
}
return false;
}
}
Once the class has been created you need to add it to your ApplicationInsights.config file.
Replace this line:
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>
with a link to your class:
<TelemetryChannel Type="XXX.RequestFilterChannel, XXX" />
Alternatively, you can disable the automated request collection and keep only exception auto-collection, just remove the RequestTrackingModule line from applicationinsights.config.
If you still need to collect some of the requests, not just filter all out, you can then call TrackRequest() (in the object of TelemetryClient class) from your code in the appropriate place after you know that you certainly need to log this request to AI.
Update: Filtering feature has been released some time ago and allows for exclusion of certain telemetry items way easier.
I am implementing OWIN authentication on a mysql backend, I dont thnk thats a problem as my registration work pretty well. I have basically worked off this post (i.e. nicked most of the code).
I am also using DI via autofac so I have changed a few things around to inject dependencies into the SimpleAuthorizationServerProvider
THE PROBLEM
I post grant_type=password, username and password to http://localhost/myappurl/token and I get back "error":"invalid_client". I get no hits when I try to debug so its probably failing in the library and not getting to my own code. Does anyone know why this would be?
Please pardon the lengthy code, I have no idea where the issue could be so I have posted everything I think is relevant, if anyone needs to see more code, please ask.
SimpleAuthorizationServerProvider
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly IUserService _userService;
public SimpleAuthorizationServerProvider(IUserService userService)
{
_userService = userService;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var authenticate = await _userService.FindUser(context.UserName, context.Password);
if (!authenticate)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
Startup
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app, (IOAuthAuthorizationServerProvider)config.DependencyResolver.GetService(typeof(IOAuthAuthorizationServerProvider)));
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app, IOAuthAuthorizationServerProvider provider)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(90),
Provider = provider,
ApplicationCanDisplayErrors=true,
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
IocConfig
public static class IocConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// Configure the container
// Register individual components
builder.Register(c => new MySQLContext()).As<IMySqlContext>().InstancePerRequest();
builder.RegisterType<SimpleAuthorizationServerProvider>().As<IOAuthAuthorizationServerProvider>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
You have a lot of code there, so it's not easy to isolate the problem. As a first step, consider removing the code for Autofac DI and see if that makes any difference. It's hard to tell what the problem might be otherwise.
If the issue is indeed related to the DI code, then perhaps this should be a raised as a separate question. In that case, try to create a small code example that demonstrates the issue succinctly. People are more likely to help if the problem code is short and to the point.
Make sure that you've set up SSL for your site. I had a similar issue and the problem was that I was not using SSL.
With MVC4 I was able to create and register a global action filter that would check the model state prior to the action's execution and return the serialized ModelState before any damage could be done.
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
However, with MVC5, I am having trouble finding Request and therefore CreateErrorResponse
public override void OnActionExecuting(ActionExecutingContext nActionExecutingContext)
{
if (!nActionExecutingContext.Controller.ViewData.ModelState.IsValid)
{
nActionExecutingContext.Result = // Where is Request.CreateErrorResponse ?
}
}
I realize that I could create a custom response class to assign to Result but I'd rather use what's built-in if CreateErrorResponse is still available.
Any idea where I can find it relative to an ActionExecutingContext in MVC5 / Web API 2?
I know this is an old question but I recently had the same problem and solved it using
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
Is there some configuration or available module in Spring Security to limit login attempts (ideally, I'd like to have an increasing wait time between subsequent failed attempts)? If not, which part of the API should be used for this?
From Spring 4.2 upwards annotation based event listeners are available:
#Component
public class AuthenticationEventListener {
#EventListener
public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {
String username = (String) event.getAuthentication().getPrincipal();
// update the failed login count for the user
// ...
}
}
Implement an AuthenticationFailureHandler that updates a count/time in the DB. I wouldn't count on using the session because the attacker is not going to be sending cookies anyway.
I recently implemented a similar functionality to monitor login failures using JMX. Please see the code in my answer to question Publish JMX notifications in using Spring without NotificationPublisherAware. An aspect on the authenticate method of authentication provider updates MBean and works with a notification listener (code not shown in that question) to block user and IP, send alert emails and even suspend the login if failures exceed a threshold.
Edit
Similar to my answer to question Spring security 3 : Save informations about authentification in database, I think that capturing an authentication failure event (as opposed to customizing a handler) and storing information in database will also work and it will keep the code decoupled as well.
As suggested by Rob Winch in http://forum.springsource.org/showthread.php?108640-Login-attempts-Spring-security, I just subclassed DaoAuthenticationProvider (which could also have been done using an aspect as Ritesh suggests) to limit the number of failed logins, but you could also assert pre-conditions as well:
public class LimitingDaoAuthenticationProvider extends DaoAuthenticationProvider {
#Autowired
private UserService userService;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Could assert pre-conditions here, e.g. rate-limiting
// and throw a custom AuthenticationException if necessary
try {
return super.authenticate(authentication);
} catch (BadCredentialsException e) {
// Will throw a custom exception if too many failed logins have occurred
userService.recordLoginFailure(authentication);
throw e;
}
}
}
In Spring config XML, simply reference this bean:
<beans id="authenticationProvider"
class="mypackage.LimitingDaoAuthenticationProvider"
p:userDetailsService-ref="userDetailsService"
p:passwordEncoder-ref="passwordEncoder"/>
<security:authentication-manager>
<security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>
Note that I think that solutions which rely on accessing an AuthenticationException's authentication or extraInformation properties (such as implementing an AuthenticationFailureHandler) should probably not be used because those properties are now deprecated (in Spring Security 3.1 at least).
You could also use a service which implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> to update the record in DB.
See spring application events.
Here is my implementation, hope help.
Create a table to store any invalid login attempts.
If invalid attempts > max allowed, set UserDetail.accountNonLocked to false
Spring Security will handle the "lock process" for you. (refer to AbstractUserDetailsAuthenticationProvider)
Last, extends DaoAuthenticationProvider, and integrate the logic inside.
#Component("authenticationProvider")
public class YourAuthenticationProvider extends DaoAuthenticationProvider {
#Autowired
UserAttemptsDao userAttemptsDao;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
//if corrent password, reset the user_attempts
userAttemptsDao.resetFailAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException e) {
//invalid login, update user_attempts, set attempts+1
userAttemptsDao.updateFailAttempts(authentication.getName());
throw e;
}
}
}
For full source code and implementation, please refer to this - Spring Security limit login attempts example,
create a table to store the values of failed attempts ex : user_attempts
Write custom event listener
#Component("authenticationEventListner")
public class AuthenticationEventListener
implements AuthenticationEventPublisher
{
#Autowired
UserAttemptsServices userAttemptsService;
#Autowired
UserService userService;
private static final int MAX_ATTEMPTS = 3;
static final Logger logger = LoggerFactory.getLogger(AuthenticationEventListener.class);
#Override
public void publishAuthenticationSuccess(Authentication authentication) {
logger.info("User has been logged in Successfully :" +authentication.getName());
userAttemptsService.resetFailAttempts(authentication.getName());
}
#Override
public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
logger.info("User Login failed :" +authentication.getName());
String username = authentication.getName().toString();
UserAttempts userAttempt = userAttemptsService.getUserAttempts(username);
User userExists = userService.findBySSO(username);
int attempts = 0;
String error = "";
String lastAttempted = "";
if (userAttempt == null) {
if(userExists !=null ){
userAttemptsService.insertFailAttempts(username); }
} else {
attempts = userAttempt.getAttempts();
lastAttempted = userAttempt.getLastModified();
userAttemptsService.updateFailAttempts(username, attempts);
if (attempts + 1 >= MAX_ATTEMPTS) {
error = "User account is locked! <br>Username : "
+ username+ "<br>Last Attempted on : " + lastAttempted;
throw new LockedException(error);
}
}
throw new BadCredentialsException("Invalid User Name and Password");
}
}
3.Security Configuration
1) #Autowired
#Qualifier("authenticationEventListner")
AuthenticationEventListener authenticationEventListner;
2) #Bean
public AuthenticationEventPublisher authenticationListener() {
return new AuthenticationEventListener();
}
3) #Autowired
public void
configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
//configuring custom user details service
auth.authenticationProvider(authenticationProvider);
// configuring login success and failure event listener
auth.authenticationEventPublisher(authenticationEventListner);
}