I have a Spring Boot based micro service (PolicyService) which is protected using Spring Security OAuth2 as a resource component.
So, a check , if the user is authenticated or not is done by validating the token received in the request using Authorization Server component.
Also, internally, within the service I check for Current User's Roles and ACE for requested object (for Update , Delete and Read operations ) to
determine if the current user has required permissions for executing target operation or not. I use Spring Security method level annotations for Role check and a custom ACL Service for domain object level permissions.
Once I determine, that the user is authenticated and also has the required authorizations for the requested operation and/or object,
a policy is created in the database.
Also, I call another operation in ACL Service from Policy Service to add ACE (access control entry) for the created object and the User.
If at any point there is a failure, I throw an exception as "access denied."
I now want to orchestrate this service using a Composite service based on Apache Camel.
I want to know if it it is better to separate out the steps for checking for authorizations using ACL Service
and also adding a ACL Entry once the policy is created , as separate steps in Apache camel.
As of now, they are all consumed by the Policy Service.
Also, I now have a requirement to do a validation for the Policy being created which is currently time consuming, so I want to use messaging by sending an event to a Queue which would be monitored by a service which validates and updates the database and sends a mail accordingly based on the outcome of the validation.
I want to know if it is better to extract these different functionalities as individual steps in a Camel Route as below or use them within the Policy Service.
If I extract the Role Check to the Composite Service, that means I need to add Spring Security to the Spring Boot based Apache Camel Composite Service to secure the service.
I currently do ACL permission check (not for Create but for other operations ) using Spring Security method level annotations and custom ACL Service. I believe I may have to redo the logic in a different way within the Camel Service now.
Also, which would be a better way to invoke the Policy Validation Service using asynchronous, messaging or by raising custom events using event-sourcing.
Also, is there any support in Apache Camel for raising custom events using event-sourcing and asynchronous service invocation
I currently have a route designed as below in Camel.
<route id="createPolicy">
<from uri="direct:createPolicy"/>
<!-- Check if User has the Role(s) required for this operation , handled internally by Policy Service using Spring Security-->
<bean ref="aclClientBean" method="checkRoleForCreatePolicy(${body})"/>
<!-- Create a Policy using Policy Service -->
<bean ref="policyClientBean" method="createPolicy(${body})"/>
<!-- Add ACE for Policy Instance and Current User using ACL Service , handled internally by Policy Service using ACL Service-->
<bean ref="aclClientBean" method="addACLForPolicy(${body})"/>
<!--Validating the Policy Details-->
<!-- Option 1:Send a message to a configured Policy Validation Queue which is monitored by Policy Validation Service -->
<!-- Option 2:Send a event that Policy is created, whoever interested on Policy Creation Event will subscribe to the event
and act accordingly when notified -->
<!-- Option 3:Asynchronously invoke the Policy Validation Service and validate the passed details -->
<bean ref="policyValidationClientBean" method="validatePolicyDetails(${body})"/>
<onException>
<exception>com.company.application.exception.AuthException</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="direct:authException"/>
</onException>
<onException>
<exception>com.company.application.exception.APPException</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="direct:appException"/>
</onException>
</route>
<route id="authException">
<from uri="direct:authException"/>
<log message="Access Denied."/>
<bean ref="policyOrchestratorClientBean" method="handleFailure('Access Denied.')"/>
</route>
<route id="appException">
<from uri="direct:appException"/>
<log message="Exception invoking Service"/>
<bean ref="policyOrchestratorClientBean" method="handleFailure('Exception invoking Service')"/>
</route>
Related
I have a .net core API with multiple endpoint. I am using Identity Server 4 for authentication. Token will be generated based on correct user name and password.
In the Same API, I want to add another endpoint which should only be accessed by API call only and normal user should not be able to access the end point.
I am thinking of Policy based authorization for the endpoint.
Is it a correct approach?
There's a couple things you could do.
As you mention you can use authorization policies. If you're using OAuth; your source API can use client credential grant type to obtain a M2M token (a.k.a. machine-to-machine token). In the target service can do a check the gty claim is equal to client_credentials, and if not; return HTTP 403 response.
Use the API gateway and only expose public APIs/operations on internal services - don't expose public routes for APIs/operations that should be restricted to service-to-service calls.
Do both #1 and #2.
Yes, you need to configure your policies. For that you need to understand the difference between authentication and authorization, and setup them both. For example in our project we use several different authentication sources, and then map them to authorization policies
services.AddAuthentication()
.AddScheme<...>("scheme1", ...)
.AddScheme<...>("scheme2", ...)
...;
services.AddAuthorization(opts =>
{
opts.AddPolicy("policy1", policy => policy.AddAuthenticationSchemes("scheme1")
.<some other requirements specific to this policy>
.RequireAuthenticatedUser());
opts.AddPolicy("policy2", policy => policy.AddAuthenticationSchemes("scheme2")
.<some other requirements specific to this policy>
.RequireAuthenticatedUser());
}
After which you could just use [Authorize("policy1")] and [Authorize("policy2")]. Or you could make one policy the default by adding
opts.DefaultPolicy = new Microsoft.AspNetCore.Authorization
.AuthorizationPolicyBuilder()
.<requirements go here>
and then use [Authorize] to use the default policy, and [Authorize("policy1")] for special cases.
I am having trouble using the Pax Web Whiteboard service to register a javax.servlet.Filter to a running JaxRS endpoint registered through CXF. I have tried a few different approaches, namely registering the Filter as a service, and using the org.ops4j.pax.web.service.WebContainer to register the filter directly.
For my test, i booted karaf, and installed pax-web, webconsole, cxf and the pax-web whiteboard service.
I the registered a bundle with a blueprint:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xmlns:cxf="http://cxf.apache.org/blueprint/core"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
">
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
<jaxrs:server id="webfiltersample" address="/webfilter">
<jaxrs:serviceBeans>
<ref component-id="serviceBean" />
</jaxrs:serviceBeans>
</jaxrs:server>
<service id="servletFilterService" interface="javax.servlet.Filter">
<service-properties>
<entry key="filter-name" value="BasicWebFilter"/>
<entry key="urlPatterns" value="/*"/>
<entry key="initParams" value=""/>
</service-properties>
<bean class="test.webfilter.BasicWebFilter"/>
</service>
<bean id="serviceBean" class="test.webfilter.WebFilterSample" init-method="init" destroy-method="destroy">
<property name="bundleContext" ref="blueprintBundleContext"/>
</bean>
</blueprint>
However, this filter is never called. I have tried both using servlet names and urlpatterns, going so far as to attempt the urlpattern /*
I then tried a slightly different approach, removing the service declaration from the blueprint, and adding the filter directly though the init method of the blueprint instead:
public void init(){
logger.info("Starting Sample");
filter = new WebFilter();
ServiceReference<WebContainer> ref = bundleContext.getServiceReference(BasicWebFilter.class);
WebContainer container = bundleContext.getService(ref);
logger.info("Registering "+ filter + " with "+ container);
container.registerFilter(filter, new String[]{"/cxf/*"}, new String[]{""}, null, null);
bundleContext.ungetService(ref);
}
The method is indeed called, as reflected by the log statements, but the filter is still not executed.
So am i completely wrong in how this works? My "Application" is really just an endpoint registered to the CXF servlet. This part is working, and i can call the REST services defined therein. But no matter what i do, the filter is not executing. I am working with a few libraries here that i don't really know that well (Servlets/Filters, Pax-Web and the Writeboard extender) do i have no idea why exactly this isn't working? My guess is that there are different httpcontexts for each bundle, and that i can't simply register a filter for another bundle (CXF) in my own test bundle.
If this is true, can someone tell me how to properly go about this problem? I could get the CXF bundles bundlecontext and register the filter to that, but that seems like a terrible horrible hack.
If that is NOT the case, can someone tell me why this is not working?
You are right, every bundle should have it's own httpContext. With Pax-Web it's possible to have shared httpContextes. For this you need to enable it for the bundle initially registering the httpContext. Though in this case it's the cxf bundle that does take care of it. As the shared context is a pax-web only feature (till v6 where OSGi R6 is implemented), this won't be added to cxf as cxf tends to rely on the smallest possible solution, which is the HttpService.
Basically even though it's possible to share httpContextes with different bundles, it's not possible for you with this scenario.
I propose to use JAAS instead of shiro as a way to login and store the authentication information. You can then use this in shiro as well as in other security implementations to do the authorization.
For CXF there is a JAASLoginFeature. It can receive basic auth as well as UserNameToken. See https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=42568988
This also has the advantage that it works the same way as the standard karaf authentication. So by default you can define users and groups in etc/users.properties but you can also for example attach karaf to ldap.
If you use blueprint then you can use blueprint-authz do role based authorization using annotations. See https://github.com/apache/aries/tree/trunk/blueprint/blueprint-authz and https://github.com/apache/aries/blob/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/authz/testbundle/impl/SecuredServiceImpl.java
How can I authenticate with HTTP Basic, via the application server domain/secure realm, using a Session Bean published as a #WebService?
In a Web project one could use web.xml to map Roles to Groups, but I have no idea how to do it in a EJB-JAR project. I don't think it can be done with ejb-jar.xml.
Sample code, which works fine without the roles annotations:
#Stateless
#WebService(portName="RestrictedServicePort")
#DeclareRoles(value = "Administrators")
public class RestrictedServiceBean {
#RolesAllowed(value = "Administrators")
public String restrictedOperation() {
return "Secret information";
}
}
Error:
<faultstring>[EJB:010160]Security Violation: User: '<anonymous>' has insufficient permission to access EJB: type=<ejb>
Basic Credentials Header:
Authorization: Basic d2VibG9naWM6d2VsY29tZTE=
I suspect it must be done via vendor-specific configuration. I am using WebLogic 10.3.6, Java EE 5 / EJB 3.0.
Basic Auth via Policy
From the v10 docs:
A Web service can have zero or more WS-Policy files associated with
it. WS-Policy files follow the guidelines of the WS-Policy
specification. WebLogic Server uses WS-Policy files to specify the
details of the message-level security (digital signatures and
encryption) and reliable messaging capabilities of a Web service. You
can attach a WS-Policy file to a Web service endpoint, which means
that the policy assertions apply to all the operations of a Web
service endpoint. You can also attach a WS-Policy file to an
operation, which means that the policy assertions apply only to the
specific operation. In addition, you can attach a WS-Policy file to
the inbound or outbound SOAP message, or both.
It would appear you can attach a basic auth policy to your service:
<sp:TransportToken>
<wsp:Policy>
<sp:HttpBasicAuthentication/>
</wsp:Policy>
</sp:TransportToken>
You can apply this custom policy via the administrative console via the steps outlined here or you can consider referencing one of the Oracle-preconfigured policies.
Mapping Roles to Groups
The WebLogic (v12) documentation mentions the following when discussing usage of #RolesAllowed in an EJB:
You can also use the annotation to explicitly declare roles that are implicitly declared if you use the #RolesAllowed annotation on the class or a method of the class.
You create security roles in WebLogic Server using the Administration Console. For details, see "Manage Security Roles" in the Oracle WebLogic Server Administration Console Help.
The Manage Security Roles section continues on to discuss scoped roles.
You can then create a scoped role for a specific EJB that contains highly sensitive business logic. When you create a policy for the EJB, you can specify that only the scoped role can access the EJB.
More information on managing scoped roles is here.
Solved adding the role mapping as it is done in any web module, but using the proprietary weblogic-ejb-jar.xml, as follows:
<wls:security-role-assignment>
<wls:role-name>Administrators</wls:role-name>
<wls:principal-name>myweblogicgroup</wls:principal-name>
</wls:security-role-assignment>
The "myweblogicgroup" is the group created in the WebLogic security realm for which the system user used to authenticated to the web service is associated.
This link helped me.
I have a CAS 3.4.9 using the login webflow.
I need to call directly the login webflow at a particular action/view.
How can it be done?
If it is not possible (I believe a security reason), How can have on CAS another "service" using another webflow?
And in this manner, what is the link I must use to call it?
Thank you.
You have two options. Extending the class in which you want to make the call, for instance at generateServiceTicket, or create a new class and inject your class into the CAS login webflow.
I have injected a trap in my CAS login webflow to check to see if a user has accepted a policy in the last 365 days.
Normally in the warn decision state, it will return the redirect action state, but instead I am trapping the user so the policy will be checked.
<decision-state id="warn">
<if test="flowScope.warnCookieValue" then="showWarningView" else="checkPolicy" />
</decision-state>
It then transitions into my checkPolicy state
<action-state id="checkPolicy">
<evaluate expression="checkPolicyAction"/>
<transition on="success" to="redirect"/>
<transition on="error" to="viewLoginForm"/>
<transition on="redirectPolicy" to="redirectPolicy"/>
<transition on="gateway" to="redirectPolicy"/>
</action-state>
The expression checkPolicyAction is defined in the cas-servlet.xml to the java class which executes the doExecute method and returns back to the webflow various states as you see in the previous xml. Just to top it off, redirectPolicy redirects the user to a new service that will then have them accept the policy and they can then continue on to what they intended to do.
Take a look at https://github.com/Unicon/cas-password-manager - This is where a company has extended the login-webflow of CAS to trap for password updates. This is where I got most of my ideas on how to trap the user. Also the CAS User Manual https://wiki.jasig.org/display/CASUM/ is a great resource.
I have some problems in the next situation:
I have wso2esb and a there is proxy-service in the esb.
I call this proxy with parameters with parameter, e.g.
http://host:9643/service/myproxy?domain=first.
After that my proxy need to get to the next endpoint: http://first.mysite.com
if we have http://host:9643/service/myproxy?domain=second we will have to get to the http://second.mysite.com
You get your parameter inside the proxy service using.
<property name="domain" value="application/x-www-form-urlencoded" scope="axis2"/>
And then you need to use switch mediator inside proxy service's insequence and then based on the case you need use send mediator to send the message to required endpoing.
This will be helpful to understand the scenario.
http://docs.wso2.org/wiki/display/IntegrationPatterns/Dynamic+Router