How to get mule security context or security principal reference in mule flow - mule

Was trying out authentication and authorisation in mule and got it working. Now I want the reference to the mule security context specifically the principal object reference to be used within the flow . How to get hold of the reference to principal object in mule inside a flow?
link to mule xml

Security context is available through MuleSession and this session is available through eventContext. To get eventContext reference, following can be done.
This can be achieved by implementing Callable. Create the following java class. Now place a java component in the mule flow where this has to be invoked and configure with the created java class. Mule calls automatically onCall method which has eventContext as a parameter and no extra configuration is required to invoke.
The example java component gets the security content from session and from that it gets the security principal and stores it in a flow variable "user" which can be used by other flow elements which appear after this java component in the flow.
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
import org.mule.api.security.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
public class GetSecurityPrincipalCallable implements Callable {
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
Authentication auth = eventContext.getSession().getSecurityContext()
.getAuthentication();
UserDetails principal = (UserDetails) auth.getPrincipal();
System.out.println("username is : " + principal.getUsername());
eventContext.getMessage().setInvocationProperty("user", principal);
return null;
}
}

Related

Register dependent services on every request

I am working in Multi-tenant solution primarily there are 2 type of applications
WebAPI
Console app to process message from queue
I have implemented dependency injection to inject all services. I have crated TenantContext class where I am resolving tenant information from HTTP header and it's working fine for API, but console application getting tenant information with every message (tenant info is part of queue message) so I am calling dependency injection register method on every incoming message which is not correct, do you have any suggestion/solution here?
The way I am resolving ITenantContext in API
services.AddScoped<ITenantContext>(serviceProvider =>
{
//Get Tenant from JWT token
if (string.IsNullOrWhiteSpace(tenantId))
{
//1. Get HttpAccessor and processor settings
var httpContextAccessor =
serviceProvider.GetRequiredService<IHttpContextAccessor>();
//2. Get tenant information (temporary code, we will get token from JWT)
tenantId = httpContextAccessor?.HttpContext?.Request.Headers["tenant"]
.FirstOrDefault();
if (string.IsNullOrWhiteSpace(tenantId))
//throw bad request for api
throw new Exception($"Request header tenant is missing");
}
var tenantSettings =
serviceProvider.GetRequiredService<IOptionsMonitor<TenantSettings>>();
return new TenantContext(tenantId, tenantSettings );
});
Create two different ITenantContext implementations. One for your Web API, and one for your Console application.
Your Web API implementation than might look as follows:
public class WebApiTenantContext : ITenantContext
{
private readonly IHttpContextAccessor accessor;
private readonly IOptionsMonitor<TenantSettings> settings;
public WebApiTenantContext(
IHttpContextAccessor accessor,
IOptionsMonitor<TenantSettings> settings)
{
// Notice how the dependencies are not used in this ctor; this is a best
// practice. For more information about this, see Mark's blog:
// https://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/
this.accessor = accessor;
this.settings = settings;
}
// This property searches for the header each time its called. If needed,
// it can be optimized by using some caching, e.g. using Lazy<string>.
public string TenantId =>
this.accessor.HttpContext?.Request.Headers["tenant"].FirstOrDefault()
?? throw new Exception($"Request header tenant is missing");
}
Notice that this implementation might be a bit naive for your purposes, but hopefully you'll get the idea.
This class can be registered in the Composition Root of the Web API project as follows:
services.AddScoped<ITenantContext, WebApiTenantContext>();
Because the WebApiTenantContext has all its dependencies defined in the constructor, you can do a simple mapping between the ITenantContext abstraction and the WebApiTenantContext implementation.
For the Console application, however, you need a very different approach. The WebApiTenantContext, as shown above, is currently stateless. It is able to pull in the required data (i.e. TenantId) from its dependencies. This probably won't work for your Console application. In that case, you will likely need to manually wrap the execution of each message from the queue in a IServiceScope and initialize the ConsoleTenantContext at the beginning of that request. In that case, the ConsoleTenantContext would look merely as follows:
public class ConsoleTenantContext : ITentantContext
{
public string TenantId { get; set; }
}
Somewhere in the Console application's Composition Root, you will have to pull messages from the queue (logic that you likely already have), and that's the point where you do something as follows:
var envelope = PullInFromQueue();
using (var scope = this.serviceProvider.CreateScope())
{
// Initialize the tenant context
var context = scope.ServiceProvider.GetRequiredService<ConsoleTenantContext>();
content.TenantId = envelope.TenantId;
// Forward the call to the message handler
var handler = scope.ServiceProvider.GetRequiredService<IMessageHandler>();
handler.Handle(envelope.Message);
}
The Console application's Composition Root will how have the following registrations:
services.AddScoped<ConsoleTenantContext>();
services.AddScoped<ITenentContext>(
c => c.GetRequiredServices<ConsoleTenantContext>());
With the registrations above, you register the ConsoleTenantContext as scoped. This is needed, because the previous message infrastructure needs to pull in ConsoleTenantContext explicitly to configure it. But the rest of the application will depend instead on ITenantContext, which is why it needs to be registered as well. That registration just forwards itself to the registered ConsoleTenantContext to ensure that both registrations lead to the same instance within a single scope. This wouldn't work when there would be two instances.
Note that you could use the same approach for Web API as demonstrated here for the Console application, but in practice it's harder to intervene in the request lifecycle of Web API compared to doing that with your Console application, where you are in full control. That's why using an ITenantContext implementation that is itself responsible of retrieving the right values is in this case an easier solution for a Web API, compared to the ITenantContext that is initialized from the outside.
What you saw here was a demonstration of different composition models that you can use while configuring your application. I wrote extensively about this in my series on DI Composition Models on my blog.

How to Import Data from SAP using wsdl file and also how to consume the proxy class generated from it

Can somebody please explain me how to use the proxy class as I don't understand it, also I have an Interface in the proxy class how should I implement it to access the method described in IBinding
The generated code for the proxy class is as given below:
public interface IBinding {
/// <remarks/>
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://sap.com/xi/A1S/Global/QueryProjectIn/FindProjectByElementsRequest", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute("ProjectByElementsResponse_sync", Namespace="http://sap.com/xi/SAPGlobal20/Global")]
ProjectByElementsResponseMessage_sync FindProjectByElements([System.Xml.Serialization.XmlElementAttribute(Namespace="http://sap.com/xi/SAPGlobal20/Global")] ProjectByElementsQueryMessage_sync ProjectByElementsQuery);
}
[HttpGet]
public static void Main()
{
ProjectByElementsQuerySelectionByElements query = new
ProjectByElementsQuerySelectionByElements();
ProjectByElementsQueryMessage_sync sync = new
ProjectByElementsQueryMessage_sync
{
ProjectSelectionByElements = query
};
}
This is not the way you access an SAP system since the data is typically not stored in just one table and it would circumvent any authorization checks that are available in the application framework.
So you should look for appropriate API's as you can find them on the API Hub.
Steps to create a web reference :
Visual Studio -> Add Service Reference -> paste the wsdl document path in your local machine -> click Go
A service will be visible as per the wsdl and the corresponding methods can be seen by clicking on the service name then in Advanced section a web service button is available, make a web reference by writing the name of the web reference and click on the button a web reference will automatically be added to the project.
Instantiate the reference file and access the method
for connection :
using webreference;
var service = new service();
service.Credentials = new System.Net.NetworkCredential("username", "password");
service.Url = "https://" + xxx.com";

How does one consume Bugsnag from singleton?

I have an ASP.NET core application that implements a singleton service.
I would like errors to be sent to Bugsnag so I've added IClient bugsnag to my constructor but am getting the following error during startup:
Cannot consume scoped service 'Bugsnag.IClient' from singleton
I cannot find anything in the Bugsnag docs that mentions IClient being scoped or how to construct a singleton instance to use in my application.
As mentioned in the comments, a possible solution would be to use IServiceScopeFactory to create a scope to use in the singleton. This is not ideal because the whole reason for using Bugsnag is to have something that catches all unhandled errors in the application and reports them to a central point for monitoring.
UPDATE: since posting the question I came across a GitHub issue addressing this problem.
In short, you couldn't register the service as singleton , since the IClient has been registered as scoped but it called in the singleton service.
When we have a scoped instance, each time we load the page, a new instance of our ChildService is created and inserted in the parent service.
Whereas when we do a singleton, it keeps the exact same instance (Including the same child services). When we make the parent service a singleton, that means that the child service is unable to be created per page load.
ASP.NET Core is essentially stopping us from falling in this trap of thinking that a child service would be created per page request, when in reality if the parent is a singleton it’s unable to be done. This is why the exception is thrown.
If you want to use iclient in the singleton service, it's impossible. The right way is make that singleton service to scoped.
Update:
As #JHBonarius says, we could inject the IServiceScopeFactory to the singleton sercive and manage the scope service.
More details, you could refer to below codes:
public class Singleton : ISingleton
{
private readonly IServiceScopeFactory scopeFactory;
public Singleton(IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
}
public void MyMethod()
{
using(var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<yourservice>();
// when we exit the using block,
// the IServiceScope will dispose itself
// and dispose all of the services that it resolved.
}
}
}

In Axis2/Rampart, how can I get SAML Assertion in PasswordCallBackHandler

I am securing my SOAP based Web Services using STS. The tokens are SAML 1.0 tokens. The SAML tokens are added in SOAP Header as security header. I need the SAMLAssertions as I need to get the nameIdentifier from the SAMLAssertion.
Can I get hold of the SAMLAssertion in PasswordCallBackHandler class. Is there any other way of doing it.
Finally I was able to identity a way to do what I wanted. I will list down the solution point wise :
Its not possible via Password CallBackHandler as axis does not give access to the MessageContext.
Solution is to create a Custom Handler class which extends org.apache.axis2.handlers.AbstractHandler . Since in my case its a SAML2 Security Token, I wanted my handler to be called 'post-security' phase in 'InFlow' phaseorder. This ensures that the security header has passed the security phase. The handler class has a invoke method which has a MessageContext as its parameter. MessageContext gives you access to the whole SOAPEnvelope and its content. Following is the skeleton code you can build on :
public class LIMSConHandler extends AbstractHandler {
private Log LOG = LogFactory.getLog(LIMSConHandler.class);
public InvocationResponse invoke(MessageContext ctx) throws AxisFault {
//following code gives you access to the soapEnvelope
SOAPEnvelope msgEnvelope = ctx.getEnvelope();
SOAPHeader msgHeader = msgEnvelope.getHeader();
//add your logic to extract the security header and SAML assertion
return InvocationResponse.CONTINUE;
}
Bind this handler to the 'Post-Security' custom phase in axis2.xml
<phaseOrder type="InFlow">
.........
<phase name="Security"/>
<phase name="PostSecurity">
<handler name="LIMSConHandler" class="labware.web.ws.control.LIMSConHandler"/>
I welcome input on this.

Mule ESB Server 3.6.1 - HTTP Component URI Params via GET method to Java Component

I am new to Mule ESB... Using Anypoint Studio, how will I be able to access a HTTP GET params in a Java Component? An example would be great!
You can access inbound properties as follows:
import java.util.Map;
import org.mule.api.MuleEventContext;
import org.mule.api.MuleMessage;
import org.mule.api.lifecycle.Callable;
public class MyComponent implements Callable{
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
MuleMessage message = eventContext.getMessage();
Map uriParams = message.getInboundProperty("http.uri.params");
String name = (String) uriParams.get("name");
...
}
}
Where 'name' is the name of the URI param you want to access. If you want to access other inbound properties, replace 'http.uri.params' with the inbound property you want to access. HTH