spring oauth and client credentials M2M calls - spring-cloud

I have a front end website that is secured using spring-cloud-secuirty with spring-cloud-oauth2 . All my backend resources are secured using #EnableResourceServer .
All requests to these resources services coming from UI are authorized through the Zuul gateway, but my problem is with back end tasks that are scheduled to run on daily bases or the one are triggered by email. These tasks are not authorized and as I understood from reading they should be authenticated as client_credentials . But i am not able to figure out how to configure feign clients to get the access code before trying to communicate with secured resources.
I have created a sample project , in this project every thing is working except the task service

Adding the below interceptor did the trick but i am not sure this is the best solution
#Component
public class Interceptor implements RequestInterceptor {
private final OAuth2RestTemplate template;
public Interceptor(ClientCredentialsResourceDetails oauth2RemoteResource) {
template = new OAuth2RestTemplate(oauth2RemoteResource, new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
}
#Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Authorization", "bearer " + template.getAccessToken().getValue());
}
}
Better Approach
After more reading I found that spring-cloud-security already have an interceptor so we just need to declare a bean of type OAuth2FeignRequestInterceptor as below
#Configuration
#EnableOAuth2Client
#Slf4j
public class OAuth2FeignAutoConfiguration {
#Bean
public OAuth2FeignRequestInterceptor oAuth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext, OAuth2ProtectedResourceDetails details) {
return new OAuth2FeignRequestInterceptor(oauth2ClientContext,details);
}
}

Related

How to use Sustainsys.Saml2.AspNetCore2 in existing net core app?

I'm trying to use Sustainsys.Saml2 and Sustainsys.Saml2.AspNetCore2 library provided by this saml2 library to implement both IDP initiated and SP initiated scenarios.
After referring sample appliation things I did so far:
1. Refer latest Sustainsys.Saml2.AspNetCore2 and Sustainsys.Saml2 via nuget
2. Modified Startup.cs to add new options
3. Created MVC controller with ACS end point
Things I'm trying to understand:
1. Do I need to Initiated Saml2Handler so that I can hit HandleRequestAsync() end point of library.
2. How to retrive principal/claims
3. For sp initiated case when end point identifies request is not authenticated how to redirect request to IDP?
ConfigureServices method in startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddSaml2(options =>
{
options.SPOptions.EntityId = new EntityId("https://localhost:3131/Saml2");
options.IdentityProviders.Add(
new IdentityProvider(
new EntityId("http://localhost:52071/Metadata"), options.SPOptions)
{
LoadMetadata = true
});
options.SPOptions.ServiceCertificates.Add(new X509Certificate2("Sustainsys.Saml2.Tests.pfx"));
});
}
**SSO Controller**
[Authorize(AuthenticationSchemes = "Saml2")]
public class SsoController : Controller
{
public SingleSignOnController(ILogger logger)
{
}
[Route("saml2/ACS")]
[HttpPost]
public ActionResult ACS()
{
try
{
// Is request authenticated here by library?
// I tried hitting this end point from stud idp portal, but it is
throwing " MVC Exception Handler: The method or operation is not implemented. at Sustainsys.Saml2.AspNetCore2.Saml2Handler.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService"
}
catch (Exception e)
{
}
}
}
Do I need to create/implement Custom Saml2Handler and inject it in SSo controller? I could not find exact end point in this ASPNETSAMPLE project for saml2/ACS?
What I'm missing ?
The Acs endpoint is built into the handler. Remove your SsoController.
Check the asp.net core sample applications in the repo for an example on how to configure. The AspNetCore2 package contains a handler that works the same as any other external authentication handler for Asp.NET Core. You initiate the sign in sequence by an authentication challenge.

Force ASP .Net Web API to block HTTP requests with Error (403)

I would like to configure my project to not allow http requests with the following restrictions:
It must be a global restriction for all APIs (via web.config, script in the installer, etc.)
It must be hard coded(not pressing "Require SSL" on the APP in the IIS)
No "redirect"- just return error (403)
my ideal option would be to configure "Require SSL" by a script which runs in the installer.
This can be accomplished by writing a simple ActionFilter that inspects the request and responds when the scheme is not set to ssl. A very minimal implementation may look something like:
public class RequireHttpsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
To make this apply everywhere, you'll likely want to register it as a global filter in the WebAPI configuration when your application is bootstrapping. That would look something like:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new RequireHttpsAttribute());
// ... More configuration ...
}
}
If you search the web a bit, you can find many examples of similar filters with more robust logic that may better meet your needs.

How to enable Cross Origin Resource Sharing (CORS) in a Fantom / afBedSheet REST service?

I am developing a REST API with Fantom and afBedSheet. I need to allow cross-origin resource sharing so that I can call my RESTful services via AJAX from the UI which runs on a different web container on a different port.
I am currently doing this in request handler methods:
res.headers["Access-Control-Allow-Origin"] = "http://localhost:8080"
But as the API grows and the number of request handlers grow, it is no longer practical. I'm wondering how can I inject that header in every response. I have Googled the question but only found a reference to a document from a very old version of afBedSheet which doesn't seem relevant anymore. Can anyone provide an example, please?
CORS has to be set up manually but as mentioned, it's not that difficult. Anything that becomes repetitive in request handler methods can usually be squirrelled away somewhere, and setting HTTP response headers is no different. These can be set via BedSheet Middleware:
using afIoc
using afBedSheet
const class CorsMiddleware : Middleware {
#Inject private const HttpRequest req
#Inject private const HttpResponse res
#Inject private const ResponseProcessors processors
new make(|This|in) { in(this) }
override Void service(MiddlewarePipeline pipeline) {
// echo back in the response, whatever was sent in the request
res.headers["Access-Control-Allow-Origin"] = req.headers["Origin"]
res.headers["Access-Control-Allow-Methods"] = req.headers["Access-Control-Request-Method"]
res.headers["Access-Control-Allow-Headers"] = req.headers["Access-Control-Request-Headers"]
// deal with any pre-flight requests
if (req.httpMethod == "OPTIONS")
processors.processResponse(Text.fromPlain("OK"))
else
pipeline.service
}
}
Note that the above will enable CORS on all requests - handy for dev, but for live code you should be more choosy and validate any given Origins, Methods, and Headers.
BedSheet Middleware should be contributed to the MiddlewarePipeline service:
#Contribute { serviceType=MiddlewarePipeline# }
static Void contributeMiddleware(Configuration config) {
config.set("myApp.cors", config.autobuild(CorsMiddleware#)).before("afBedSheet.routes")
}
Note that CorsMiddleware is inserted into the pipeline before BedSheet routes to ensure it gets executed.

Keycloak Custom Validation Output messages

I'm using jboss keycloak 1.5 final version.
I developed my custom user federation provider interfacing with keycloak properties and my user enterprise database.
My need is to send up to user the login interface custom error messages based on particular specific error related to my legacy user db.
I saw keycloak themes have a resources folder by which i can localize and add new messages. Then i can reference them by angular js using
$myMessage
notation. The problem is i want to rise up a message from keycloak server. My user federation provider implements UserFederationProvider interface. So i should have to override:
#Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
LOGGER.info("validCredentials(realm, credential)");
return CredentialValidationOutput.failed();
}
which seems to be the method i was looking for just because CredentialValidationOutput contains custom messages to be sent as validation output. The problem is this method is never called.
Why?
I'll post the answer found on my own.
It's necessary to develop your own Authenticator. For example refer to Keycloak UsernameAndForm and UsernameAndFormFactory implementation.
You can find them on Keycloak github source code:
https://github.com/keycloak/keycloak/tree/master/services/src/main/java/org/keycloak/authentication/authenticators/browser
The main validation method are:
public boolean validateUserAndPassword(AuthenticationFlowContext context, MultivaluedMap<String, String> inputData) {
...
}
public boolean validatePassword(AuthenticationFlowContext context, UserModel user, MultivaluedMap<String, String> inputData) {
...
}
From your custom user federation provider you can throw your custom exception and catch them in the two methods above adding:
catch (YourCustomException ex){
...
Response challengeResponse = context.form()
.setError("YOUR ERROR MESSAGE", me.getMandator()).createLogin();
context.failureChallenge(AuthenticationFlowError.INVALID_USER, challengeResponse);
return false;
}
Of course in your project you have to add
META-INF/service/org.keycloak.authentication.AuthenticatorFactory
In which you specify the full qualified name of your AuthenticatorFactory.
For a valid guide make reference to Keycloak User Guide 1.6.1 Final. Chapter 33.3

CometD Subscription Listeners

I’m having a problem processing Subscription Requests from Clients and carrying out some processing based on the request. I’d like to be able to invoke a method and carry out some processing when an incoming subscription request is received on the Server. I’ve had a look at the following CometD documentation and tried the example outlined in “Subscription Configuration Support” but I’m not having much luck.
http://www.cometd.org/documentation/2.x/cometd-java/server/services/annotated
I’ve already created the Bayeux Server using a Spring Bean and I’m able to publish data to other channel names I’ve created on the Server side. Any help or additional info. on the topic would be appreciated!
The code example I’m using:
#Service("CometDSubscriptionListener")
public class CometDSubscriptionListener {
private final String channel = "/subscription";
private static final Logger logger = Logger.getLogger(CometDSubscriptionListener.class);
private Heartbeat heartbeat;
#Inject
private BayeuxServer bayeuxserver;
#Session
private ServerSession sender;
public CometDSubscriptionListener(BayeuxServer bayeuxserver){
logger.info("CometDSubscriptionListener constructor called");
}
#Subscription(channel)
public void processClientRequest(Message message)
{
logger.info("Received request from client for channel " + channel);
PublishData();
}
Have a look at the documentation for annotated services, and also to the CometD concepts.
If I read your question correctly, you want to be able to perform some logic when clients subscribe to a channel, not when messages arrive to that channel.
You're confusing the meaning of the #Subscription annotation, so read the links above that should clarify its semantic.
To do what I understood you want to do it, you need this:
#Service
public class CometDSubscriptionListener
{
...
#Listener(Channel.META_SUBSCRIBE)
public void processSubscription(ServerSession remote, ServerMessage message)
{
// What channel the client wants to subscribe to ?
String channel = (String)message.get(Message.SUBSCRIPTION_FIELD);
// Do your logic here
}
}