CAS SSO building a custom authentication handler - cas

There are two different groups of people in my workspace.
Those who are regular staff will have their ID beginning with an s and followed by a sequence of digits. e.g. s123456789.
Those who are non-regular staff will have their ID in all digits. e.g. 81234567.
Regular staff will be authenticated against LDAP server. Non-regular staff will be authenticated via a RESTful api.
I want to add a service that implements the above strategy.
It will first check if the ID beginning with an s if so it then auth using LDAP.
If not, auth using rest api.
After looking up CAS official documentation, I think only custom authentication handler can achieve this.
But how do I get started with cas-overlay-template? Any direction?

To design custom authentication handlers, the overall tasks may be categorized as such:
Design the authentication handler
public class MyAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
}
Register the authentication handler with the CAS authentication engine.
public class MyAuthenticationEventExecutionPlanConfiguration
implements AuthenticationEventExecutionPlanConfigurer {
#Autowired
private CasConfigurationProperties casProperties;
#Bean
public AuthenticationHandler myAuthenticationHandler() {
var handler = new MyAuthenticationHandler();
return h;
}
#Override
public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) {
plan.registerAuthenticationHandler(myAuthenticationHandler());
}
}
Tell CAS to recognize the registration record and authentication configuration.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.cas.MyAuthenticationEventExecutionPlanConfiguration
See this link for notes and details.

Related

How to access the Azure Web App configuration in a static web page

I have a simple set up:
Azure Web App, running a static react app
Azure Functions App, the API layer that accesses the database and that is called from the static web app
Both Web App and Functions App have a deployment slot feature, where you deploy in a separate slot first and if everything works well, you can swap the artifact in your slot and the current version, with no downtime. I really want to use this to its fullest.
I'd like to use the Web App configuration to inject the root uri of the API, have it point to the API in the corresponding slot. So the production-staging static site, should point to the production-staging API.
But here's the main problem: I cannot access the Web App configuration from my react app. I have to insert the root uri at build time, which disables the swap feature for the Web App (since it would still be pointing to staging).
Accessing the configuration works fine for the Functions App; I'm assuming because it's running node.
The Web App Configuration are available as environment variables on the server. You won't be able to access those variables within your static react app that is running on the client.
You will need some kind of middleware that is able to read and expose the environment variables through an API.
You can use ASP.NET Core with the React project template to create both, an ASP.NET Core project that acts as an API and a standard CRA React project to act as a UI, but with the convenience of hosting both in a single app project that can be built and published as a single unit. (Source).
Then you will have to write a little controller that exposes the configurations. Here an example:
public class MyOptions
{
public string ApiUri { get; set; }
}
[ApiController]
[Route("[controller]")]
public class ConfigurationController : ControllerBase
{
private readonly MyOptions _options;
public ConfigurationController(IOptions<MyOptions> options)
{
_options = options.Value;
}
[HttpGet]
public MyOptions GetConfigurations()
{
return _options;
}
}
You also need to configure the options within the startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection(nameof(MyOptions)));
services.AddControllers();
}
Now you can set your initial value within the appsettings.json:
{
"MyOptions": {
"ApiUri" : "https://myapp.domain.com/api"
}
}
And you are also able to overwrite the options using the Azure Web App Configurations (the middleware is configured to also use environment variables and that environment variables overwrite appsettings.json)
Now the last thing you have to do is to retrieve the settings within your static UI using:
window.location.host + "/api/configuration"
Client code cannot access appsettings.json. In react you can use.env files to store your configurations. You can create.env files for each environment you want to support and in the build script you can mention which.env file to use for each environment.

.net core, n-layered app, should services layer have dependency on Microsoft.Extensions.Options.dll

Straightforward question is: are Microsoft.Extensions.Options.IOptions meant to be used only within the context of umbrella app (web app in this case) or in class libraries also?
Example:
In a n-layered, asp.net core app we have services layer that is dependant on some settings coming from appsettings.json file.
What we first started with is something along these lines in Startup.cs:
services.Configure<Services.Options.XOptions>(options =>
{
options.OptionProperty1 = Configuration["OptionXSection:OptionXProperty"];
});
And then in service constructor:
ServiceConstructor(IOptions<XOptions> xOptions){}
But that assumes that in our Service layer we have dependecy on Microsoft.Extensions.Options.
We're not sure if this is recomended way or is there some better practice?
It just feels a bit awkward our services class library should be aware of DI container implementation.
You can register POCO settings for injection too, but you lose some functionalities related to when the appsettings.json gets edited.
services.AddTransient<XOptions>(
provider => provider.GetRequiredService<IOptionsSnapshot<XOptions>>().Value);
Now when you inject XOptions in constructor, you will get the class. But when your edit your appsettings.json, the value won't be updated until the next time it's resolved which for scoped services would be on next request and singleton services never.
On other side injecting IOptionsSnapshot<T> .Value will always get you the current settings, even when appsettings.json is reloaded (assuming you registered it with .AddJsonFile("appsettings.json", reloadOnSave: true)).
The obvious reason to keep the functionality w/o pulling Microsoft.Extensions.Options package into your service/domain layer will be create your own interface and implementation.
// in your shared service/domain assembly
public interface ISettingsSnapshot<T> where T : class
{
T Value { get; }
}
and implement it on the application side (outside of your services/domain assemblies), i.e. MyProject.Web (where ASP.NET Core and the composition root is)
public class OptionsSnapshotWrapper<T> : ISettingsSnapshot<T>
{
private readonly IOptionsSnapshot<T> snapshot;
public OptionsSnapshotWrapper(IOptionsSnapshot<T> snapshot)
{
this.snapshot = snapshot ?? throw new ArgumentNullException(nameof(snapshot));
}
public T Value => snapshot.Value;
}
and register it as
services.AddSingleton(typeof(ISettingsSnapshot<>), typeof(OptionsSnapshotWrapper<T>));
Now you have removed your dependency on IOptions<T> and IOptionsSnapshot<T> from your services but retain all up advantages of it like updating options when appsettings.json is edited. When you change DI, just replace OptionsSnapshotWrapper<T> with your new implementation.

Custom Policy-Based Authorization in asp.net

I am working on custom policy based authorization in asp.net web application
I followed the steps given in the below link
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies
I have created authorization requirement and Authorization Handlers
for registering handlers in the service collection the ConfigureService method has to be added in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("Over21",
policy => policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
But, when I debug the code this ConfigureService method is not invoked.
Do I need to add any reference?
Try adding Authorization services before adding MVC services.

Spring Security 4.0 Content Negotiation restrictiions

I have an app that uses spring security 4.0 and i am concern now about the content negotiation response that this app could send on a REST web service i.e.
my target is to restrict the response on a global basis irrelevant of the type of the request i.e. if that would be REST http get request through MVC or some kind of websocket (although i am not sure if that apply for the websocket) the response should be only returned as a json and NOT as XML. I do not want to support xml or any negotiation format.
The reason i am concerned about this is because i watched
a video on infoq made by a gentlemen called Mike Wiesner about spring application security pitfalls.
i know i can use in this case the annotation #RequestMapping and the sub-option "produces", i.e. something like
#RequestMapping(produces={MediaType.APPLICATION_JSON_VALUE} , value = "/target/get", method=RequestMethod.GET)
but since i have so many controllers it will be a nightmare for me to put that additional sub-option on all of them.
and i know that there are other annotations such as
#XmlTransient
#JsonIgnore
that could help me with what i want to do i.e. make some filds (getter/setters) to not be exposed in case the content negotiation changes but putting those annotations on each
getter/setter will even be bigger problem
Thus my question how do i do that on a global basis. I suppose this should be done in the MVCConfig class that extends WebMvcConfigurerAdapter?
By that i mean overriding the configureContentNegotiation method There are multiple examples doing that but those only explaing how to set up the the default behavior. My question is how do we restrict the behavior i.e. if http request is coming with "Accept" header application/xml how do i reject that on a global basis.
examples of the default behavior:
Spring boot controller content negotiation
so what i do is someting like
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
If anything else then a json comms into the http request
reject this request or smply ignore it on a global basis.
Do not send/support xml, xhtml, html etc.
}
}
I coincidentally was looking into a related issue to this question in the last couple of days. We manually configure a ContentNegotiationManager in our code base, and in that process we limit the header based portion of the Spring PPA Strategy by providing an overridden HeaderContentNegotiationStrategy that does limiting by the Accept header similar to what you want. I took a quick look at ContentNegotiationConfigurer (which I have never used) and it does not appear to provide an option for which to alter mappings for the HeaderContentNegotiationStrategy, so here is a code snippet of the way we setup our ContentNegotiationManager.
#Bean
public ContentNegotiationManager contentNegotiationManager() {
//Supply a Map<String, org.springframework.http.MediaType>
PathExtensionContentNegotiationStrategy pathBased = new PathExtensionContentNegotiationStrategy(supportedMediaTypes());
//Supply a Map<org.springframework.http.MediaType, org.springframework.http.MediaType>
HeaderContentNegotiationStrategy headerBased = new MappingHeaderContentNegotiationStrategy(contentTypeMap());
FixedContentNegotiationStrategy defaultStrategy = new FixedContentNegotiationStrategy(MediaType.APPLICATION_JSON);
return ContentNegotiationManager(pathBased, headerBased, defaultStrategy);
return retval;
}
That bean is created in our config that overrides WebMvcConfigurerAdapter and is injected into this bean:
#Bean
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setRemoveSemicolonContent(false);
handlerMapping.getFileExtensions().add("json");
handlerMapping.setUseRegisteredSuffixPatternMatch(true);
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
return handlerMapping;
}

RESTful web service: java.lang.NullPointerException service.AbstractFacade.findAll

I created a simple XML web service using NetBeans 7's "RESTful Web Services from Database..." wizard. At this point, I want to publish a list of users from the associated mySQL database.
When I attempt to access the service via its URL (http://localhost:8080/database/resources/users), I get an error that reads "java.lang.NullPointerException". The stack trace:
service.AbstractFacade.findAll(AbstractFacade.java:41)
service.UserFacade.findAll(UserFacade.java:51)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:165)
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67)
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:276)
com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:83)
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:133)
com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:71
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1171) com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1103) com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1053)
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1043)
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:406)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:477)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:662)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
User entity:
package entities;
...
#Entity
#Table(name="users")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Users.findAll", query = "SELECT u FROM Users u"),
...
I've also changed the named query to User.findAll in case the names needs to align with the entity's name. This did not solve the problem.
I'm not certain if it is 'normal' or not, but the wizard created a fairly sparse UserFacade class; I added the missing methods after researching the topic. Furthermore, the javax.ejb.Stateless package seems to be missing (perhaps not on my workstation's CLASSPATH); this is the reason that the #Stateless annotation is disabled.
UserFacade class:
//#Stateless
#Path("users")
public class UserFacade extends AbstractFacade<User> {
#PersistenceContext(unitName="databasePU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public UserFacade() {
super(User.class);
}
#GET
#Path("{id}")
#Produces({"application/xml", "application/json"})
public User find(#PathParam("id") BigDecimal id) {
return super.find(id);
}
#GET
#Override
#Produces({"application/xml", "application/json"})
public List<User> findAll() {
return super.findAll();
}
}
Exception is thrown at the first line in the AbstractFacade's findAll method:
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
...
}
Questions:
Is the #Stateless annotation required for this to function?
Does this pattern require J2EE 6 rather than J2SE 6 (which is what is installed on my OS X workstation)? The 'javax.ejb' namespace seems to suggest enterprise java beans.
** edit **
Java SE 6 (1.6.0_29-b11-402)
The auto-generated query "SELECT u FROM Users u" works without any problems. As per the comment suggesting that "u" might be wrong because it doesn't represent a column, that suggestion is not correct because here "u" is an alias for the table users.
I would debug further the findAll() to check if something is null, i.e. the EntityManager.
The #Stateless annotation in the UserFacade is necessary, and removing it would probably cause the EntityManager to be null (note that I wrote "removing" because NetBeans places if for you, if you use "RestFul Web Services from Database" wizard). See here a similar question.
Regarding your latest edit: yes, these features need to be built using the Java Platform, Enterprise Edition. In particular, RESTFul web services make use of the Java API for RESTful Web Services (JAX-RS) which is included in the Java EE 6 platform as explained here.
GlassFish Server Open Source Edition is the first compatible implementation of the Java EE 6 platform specification: I suggest using this Application Server and following the tutorials linked above.
I think #ori is on the the answer. Your table Users probably don't have a column named u so you get an exception when it tries to match the column u to the database.
Change to u.* and it should work fine.