Custom authentication - security

My system has 2 subsystems. Each subsystem has different set of users. Each user has an extra field "SystemName" that can be used to know which system this user belongs to.
In the login forms (1 form for each subsystem) I added a hidden field specifying the type of the form (containing the SystemName value).
Generally, the check is rather simple:
if (user.systemName == params.systemName) {
proceed with regular login
} else {
throw standard login error
}
I tried putting that check to my custom DaoAuthenticationProvider but it has no access to "params.systemName".
Where do I put that code to make Acegi authenticate my users with this check?
Thanks in advance.

This is how I did it in Java. Extend WebAuthenticationDetails:
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.ui.WebAuthenticationDetails;
public class SystemNameWebAuthenticationDetails extends WebAuthenticationDetails {
public SystemNameWebAuthenticationDetails() {
super();
}
public SystemNameWebAuthenticationDetails(HttpServletRequest request) {
super(request);
this.systemName = request.getParameter("systemName");
}
public String getSystemName() {
return systemName;
}
private String systemName;
}
Set it in the authentication filter:
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
...
<property name="authenticationDetailsSource">
<bean class="org.acegisecurity.ui.AuthenticationDetailsSourceImpl">
<property name="clazz" value="SystemNameWebAuthenticationDetails"/>
</bean>
</property>
</bean>
Later you can access that property in the authentication process asking the details to the authentication object. Or doing this:
SecurityContextHolder.getContext().getAuthentication().getDetails()

Related

Shopware How to get SalesChannelContext in OrderWrittenEvent in order to send Mail?

I have a situation where I want to send emails from the order written event whenever an order has been updated according to some set of conditions that I will implement (for example an API response error) But unfortunately I have been unable to do so.
I first created a controller and an email service which uses the abstract email service of shopware And from my controller I'm able to send an email But when I tried to do the same in the event,I quickly realized that it wasn't doing exactly what I was expecting it to do. After some research on it, I saw that the event actually don't have access to the sales channel context so I tried multiple different ways to solve this issue but I'm still stuck. Can somebody please guide me on how I can implement that? thank you very much.
an example of what I tried is to call the store API in order to get the context of the saleschannel to use it in my sendMail function But it was giving errors such as:
request.CRITICAL: Uncaught PHP Exception TypeError: "Argument 5 passed to Swag\BasicExample\Service\EmailService::sendMail() must be an instance of Shopware\Core\System\SalesChannel\SalesChannelContext, instance of stdClass given.
I obviously understand that I have to give it a Shopware\Core\System\SalesChannel\SalesChannelContext not an STD class but how can I do that? since it doesn't really see the channel context.
If you do have an instance of OrderEntity you can rebuild the SalesChannelContext from the existing order using the OrderConverter service.
<service id="Foo\MyPlugin\Subscriber\MySubscriber">
<argument type="service" id="Shopware\Core\Checkout\Cart\Order\OrderConverter"/>
<argument type="service" id="order.repository"/>
<tag name="kernel.event_subscriber"/>
</service>
class MySubscriber implements EventSubscriberInterface
{
private OrderConverter $orderConverter;
private EntityRepository $repository;
public function __construct(
OrderConverter $orderConverter,
EntityRepository $repository
) {
$this->orderConverter = $orderConverter;
$this->repository = $repository;
}
public static function getSubscribedEvents(): array
{
return [
OrderEvents::ORDER_WRITTEN_EVENT => 'onOrderWritten',
];
}
public function onOrderWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $writeResult) {
$orderId = $writeResult->getPrimaryKey();
$criteria = new Criteria([$orderId]);
$criteria->addAssociation('transactions');
$criteria->addAssociation('orderCustomer');
$order = $this->repository
->search($criteria, $event->getContext())->first();
if (!$order instanceof OrderEntity) {
continue;
}
$salesChannelContext = $this->orderConverter
->assembleSalesChannelContext($order, $event->getContext());
// ...
}
}
}

How do I skip certain ValidateInterceptor?

I have created a VariantValueCategory and wanted to skip the ValidateInterceptor as it was not allowing me to create VariantValueCategory either by Impex or by HMC. Can any one suggest me how do I skip ValidateInterceptor or any Interceptor?
Answer for hybris >= v6
Check Mouad El Fakir's answer for previous version
You can disable interceptor through code and Impex.
Using code
You can run your save model code using sessionService.executeInLocalViewWithParams and you can use parameters to avoid to use interceptors.
There are 3 types of policies :
InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_BEANS : to disable a list of beans
InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES : to disable a kind of interceptor - validator for example
InterceptorExecutionPolicy.DISABLED_UNIQUE_ATTRIBUTE_VALIDATOR_FOR_ITEM_TYPES : to disable UniqueAttributesValidatoron a set of type
Example 1 - Disable beans
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_BEANS, ImmutableSet.of("yourDataInterceptorToDisable"));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - yourDataInterceptor interceptor is disabled
}
});
Example 2 - Disable interceptors type
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES,
ImmutableSet.of(InterceptorExecutionPolicy.DisabledType.VALIDATE));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - all validate interceptors are disabled
}
});
Example 3 - Disable by type
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_UNIQUE_ATTRIBUTE_VALIDATOR_FOR_ITEM_TYPES, ImmutableSet.of("YourType"));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - UniqueAttributesValidator not called
}
});
Using Impex
It's the same thing with impex you can add 3 parameters to achieve the same thing as code
Example 1 - Disable beans [disable.interceptor.beans='yourDataInterceptorToDisable']
INSERT_UPDATE YourType[disable.interceptor.beans='yourDataInterceptorToDisable'];isocode[unique=true];toto;titi;
;something;toto;titi;
Example 2 - Disable interceptors type [disable.interceptor.types=validate]
INSERT_UPDATE YourType[disable.interceptor.types=validate];isocode[unique=true];toto;titi;
;something;toto;titi;
Example 3 - Disable by type [disable.UniqueAttributesValidator.for.types='YourType']
INSERT_UPDATE YourType[disable.UniqueAttributesValidator.for.types='YourType'];isocode[unique=true];toto;titi;
;something;toto;titi;
Ref : https://help.hybris.com/6.3.0/hcd/9ce1b60e12714a7dba6ea7e66b4f7acd.html
Actually there are two modes of importing data with ImpEx in Hybris :
Active mode : it uses the ServiceLayer to do import. It means that actions like INSERT, UPDATE and REMOVE are performed using ModelService, thus the ServiceLayer infrastructure like interceptors and validators are triggered.
Legacy mode : it's a very quick CRUDE import, which means it's bypassing the ServiceLayer of Hybris, hence no interceptors and no validators are invoked.
So how to enable legacy mode ? will You can do this in three different ways :
In local.properties set impex.legacy.mode = true and restart the server.
<!-- local.properties -->
impex.legacy.mode = true
Or if you do import using HAC, check legacy mode checkbox :
Or set the configuration directly into theimpex like this :
INSERT_UPDATE VariantValueCategory[impex.legacy.mode=true] ;myAttribute
...
However if you want to disable completely the interceptor from being called (not just for impexes), you can replace it with a VoidInterceptor.
VoidInterceptor : it's an empty interceptor, it does nothing at all.
So if we suppose that you want to prevent this interceptor variantCategoryValidateInterceptor from being invoked, you can replace it like this :
<!-- in my*-spring.xml -->
<bean id="variantValueCategoryVoidInterceptorMapping" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="VoidInterceptor"/>
<property name="typeCode" value="VariantValueCategory"/>
<property name="replacedInterceptors" ref="variantCategoryValidateInterceptor"/>
</bean>
The simpliest way: unregisterInterceptor
Go to HAC -> Scripting Languages -> Groovy
def inteceptorMapping = spring.getBean("yourInterceptorMappingBeanId")
registry = spring.getBean("interceptorRegistry");
registry.unregisterInterceptor(inteceptorMapping);

How to skip the setting of 'filter' and 'locker' attribute if custom DirectoryScanner is used in Spring Integration 4.2.0 with XML Config

With Spring Integration 4.2.0, it mentioned that 'filter' and 'locker' must be present if custom Scanner is being used (https://jira.spring.io/browse/INT-3619).
I don't know how to set this with XML config if I simply override the listEligibleFiles() method and use the default filters provided by DefaultDirectoryScanner.
e.g.
// using the default filters
public class MyDirectoryScanner extends DefaultDirectoryScanner {
#Override
protected File[] listEligibleFiles(File directory) throws IllegalArgumentException {
return super.listEligibleFiles(directory);
}
}
<bean id="myCustomScanner"
class="com.company.MyDirectoryScanner" />
<int-file:inbound-channel-adapter directory="my_directory"
prevent-duplicates="true"
scanner="myCustomScanner"
channel="myChannel">
<int:poller fixed-rate="10"
time-unit="SECONDS" max-messages-per-poll="5" />
</int-file:inbound-channel-adapter>
It's not clear what you mean; that JIRA was to fix a bug where those properties were incorrectly overridden.
When injecting a custom scanner, you need to set those properties on your scanner rather than via the namespace.
use the default filters provided by DefaultDirectoryScanner.
The DefaultDirectoryScanner has the code:
public DefaultDirectoryScanner() {
final List<FileListFilter<File>> defaultFilters = new ArrayList<FileListFilter<File>>(2);
defaultFilters.add(new IgnoreHiddenFileListFilter());
defaultFilters.add(new AcceptOnceFileListFilter<File>());
this.filter = new CompositeFileListFilter<File>(defaultFilters);
}
So, if you would like do not use AcceptOnceFileListFilter (or any other default) you should follow with the recommendation from the Docs and use setFilter() of the DirectoryScanner contract. For this purpose there is FileListFilterFactoryBean with the setPreventDuplicates() to be set to false.
And yes, remove, please, prevent-duplicates="true" from your configuration, because it is prohibited, when scanner is in use:
Assert.state(!(this.scannerExplicitlySet && (this.filter != null || this.locker != null)),
"The 'filter' and 'locker' options must be present on the provided external 'scanner': "
+ this.scanner);
The filter can be set to null on the DefaultDirectoryScanner by the way...
I'm converting the JIRA to Documentation just to be more clear on the matter.

WCF Data Service with EF complex type

I'm just playing with EF5 and Data Services. Decided to test exposing SP. Mapped it to FirmInfo complex type. Running in this stupid error. Cannot seem to figure it out.
I have this complex type .tt template created for me
public partial class FirmInfo
{
public int FirmID { get; set; }
public string Name { get; set; }
}
I added this to expose it to MyDataService.svc.cs class:
[WebGet]
public IQueryable<FirmInfo> pSPTest(int id)
{
return CurrentDataSource.pSPTest(id).AsQueryable();
}
I can see it in browser as such:
- <pSPTest xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
- <element m:type="DB.FirmInfo">
<FirmID m:type="Edm.Int32">1</FirmID>
<Name>Firm Name</Name>
</element>
</pSPTest>
but when consuming by c# client app I keep getting this error:
The property 'element' does not exist on type 'Client.ServiceReference.FirmInfo'. Make sure to only use property names that are defined by the type.
any help appreciated
How are you consuming the result with the C# client app? If you're using the WCF Data Services client, you should be calling Execute<T>() on the DataServiceContext.
For guidance on how to use the WC Data Services client to call service operations, check out this documentation: http://msdn.microsoft.com/en-us/library/hh230677.aspx
You could also achieve this by stating the result of the operation as the collection type that you expect, like this.
var query = context.CreateQuery<ObservableCollection<wsAccountView.organisation>>("GetOrganisationsByUserName").AddQueryOption("UserName", #"'SFN\AO'");
var Organisations = query.ToList();

Using Symfony2's AccessDeniedHandlerInterface

I am trying to get my security stuff setup for symfony2 and I have it working so far, but now I need to do some more fancy things. I am currently using everything dealing with PreAuthentication (I use a third party component for logging in and session management). That part is working great in tandem with the JMS security bundle.
Now I am to the point when I want to catch the users that are throwing 403s so I can just forward them to the login page of the third party component that I am using. I think my best bet is to add an exception handler to the exception listener. I am looking at the AccessDeniedHandlerInterface.
Is this the right direction for me to be going?
How do I add this handler to the exception listener?
EDIT:
I ended up doing something similar. I created a service that is prompted on the kernel.exception event. services.yml looks like this:
services:
kernel.listener.accessDenied:
class: Fully\Qualified\Namespace\Path\To\Class
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onAccessDeniedException }
and the class it self:
<?php
namespace Fully\Qualified\Namespace\Path\To;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent,
Symfony\Component\HttpFoundation\Response,
Symfony\Component\Security\Core\Exception\AccessDeniedException;
class Class
{
public function onAccessDeniedException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
//Get the root cause of the exception.
while (null !== $exception->getPrevious()) {
$exception = $exception->getPrevious();
}
if ($exception instanceof AccessDeniedException) {
//Forward to third-party.
}
}
}
This sounds about right.
Or, if you're specifically interested in AccessDeniedException you could also define access_denied_handler within your firewall in security.yml:
security:
firewalls:
my_firewall:
# ...
access_denied_handler: kernel.listener.access_denied.handler
# ...
Then define your service in your services.xml or equivalent:
<parameters>
<parameter key="kernel.listener.security.class">Path\To\Your\Class</parameter>
</parameters>
<service id="kernel.listener.access_denied.handler" class="%kernel.listener.security.class%">
<tag name="kernel.event_listener" event="security.kernel_response" method="handle" />
</service>
The handler class:
use \Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
class MyAccessDeniedHandler implements AccessDeniedHandlerInterface
{
public function handle(Request $request, AccessDeniedException $accessDeniedException)
{
// do something with your exception and return Response object (plain message of rendered template)
}
}
You can find complete Security reference of Symfony2 here: http://symfony.com/doc/2.8/reference/configuration/security.html

Resources