I have a MacOS network extension that activates 3 network "Proxies" (TransparentProxy, AppProxy and DNSProxy).
To activate the proxies I do:
NEAppProxyProviderManager.loadAllFromPreferences {
saveToPreferences { error in
if (error) {
/* failed to save */
}
/* saved */
}
}
Now I do this 3 times (once for each proxy).
The behavior I observe is the following:
Once the "saveToPreferences()" is called for the first time the app is installed, user gets an approval popup.
Even before user clicks anything, the first 2 calls to "saveToPreferences" fail (both with the same message):
Failed to save configuration MyTransparentProxy: Error Domain=NEConfigurationErrorDomain Code=10 “permission denied” UserInfo={NSLocalizedDescription=permission denied}
The third call to "saveToPreferences()" does NOT return until a user either accepts or rejects the "allow vpn configuration" pop up.
My question is, how can I make all the calls to block the completion callback until user decision ?
For now, I figured out that this works as workaround:
In the initialization of the first proxy I do:
NEAppProxyProviderManager.loadAllFromPreferences {
saveToPreferences { error in
if (error) {
/* failed to save */
}
/* saved */
/* here I start the “next” proxies */
StartNextProxy();
}
}
In this case the first one is blocked until user accepts the pop up and once he does I start the second and the third proxies. This ensure avoidance of "permission denied" error as only one "saveToPreferences()" call waits for user approval.
This doesn’t feel like the correct method to me, is there a way for multiple proxy manager to wait for "VPN Configuration" approval event ?
Related
I want Keycloak to send an e-mail to a user whenever a user is blocked due to too many failed login attempts (see section Realm Settings -> Security defenses -> Brute force detection).
The event in question has the following properties:
Error (org.keycloak.events.Event#getError) = user_temporarily_disabled
Type (org.keycloak.events.Event#getType) = LOGIN_ERROR
How can I do that, i. e. make Keycloak send an e-mail to the user when such event occurs?
Known ways to implement it
One obvious way to do it is to write a class that implements the org.keycloak.events.EventListenerProvider interface, detect the event in its onEvent method and trigger sending of the e-mail at some custom server (i. e. send a request to that server and it will contact an SMTP server).
Second is a variation: Detect the event in the same method and somehow make Keycloak send the e-mail using Keycloak SMTP settings ("Realm settings -> Email -> Connection & Authentication").
The screenshot in this answer made met think (possibly wrongly) that there may be a way to make Keycloak send emails upon the occurrence of certain events "out of the box," i. e. without writing custom event listeners.
Update 1: If someone else wants to do this, I recommend to look at this answer. The code below worked for me.
RealmModel realm = this.model.getRealm(event.getRealmId());
UserModel user = this.session.users().getUserById(event.getUserId(), realm);
if (user != null && user.getEmail() != null) {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>" + user.getEmail());
org.keycloak.email.DefaultEmailSenderProvider senderProvider = new org.keycloak.email.DefaultEmailSenderProvider(session);
try {
senderProvider.send(session.getContext().getRealm().getSmtpConfig(), user, "test", "body test",
"html test");
} catch (EmailException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Keycloak does indeed support sending emails for events out of the box. However, it can only be configured by event (LOGIN_ERROR), and not by further filtered types (user_temporarily_disabled).
For this, you will need to implement your own EventListener, but it should be easy to heavily copy code from Keycloak's existing EmailEventListener, which you can find here: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java
In there, you'd change the implementation of L59 in onEvent(Event event) to check your two conditions (event type and error), rather than checking against some list of configured fixed events. Your event will be added to the currently running transaction, and when the transaction ends (in success or error), Keycloak will send an email via the SMTP settings that are configured in the realm.
If you want to customize the template and subject lines of the email, you'll have to provide your own freemarker templates in src/main/resources/theme-resources/templates/{html,text}. Both the html and text folder need to contain an .ftl file of the same name. Message keys for use in the template and the subject go in src/main/resources/messages/messages_{en,fr,de,...}.properties files.
With the template and messages configured, you can use one of the 2 send(...) methods available in the EmailTemplateProvider class
I've configured monolog to send errors via email as described in the symfony docs here: https://symfony.com/doc/4.3/logging/monolog_email.html
Works well with all errors happing during a request, as well as console command errors.
But it does not send emails for errors which occurred during the handling of a messenger message.
Errors are shown when running the consumer bin/console messenger:consume async -vv and they also show up in prod.log like this:
[2020-01-10 12:52:38] messenger.CRITICAL: Error thrown while handling message...
Thanks for any hints on how to set up monolog to get messenger errors emailed too.
In fact monolog swift_mailer type use SwiftMailerHandler
wish also implements reset interface and use memory spool by default wish keep all emails in buffer until it is destructed, so till the end of request :
onKernelTerminate
onCliTerminate
OR till reset method is called, which means that for messenger worker no emails will be send ever because ther's no instant flush - all of them will be kept in in-memory buffer, and probably lost if the process will be killed.
To solve this, you can just disable the default spool memory setting for swiftmailer.
Another solution is to flush your emails after WorkerMessageFailedEvent event gets fired, you can implement an event subscriber to do it for this.
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
use Symfony\Contracts\Service\ResetInterface;
/**
* Class ServiceResetterSubscriber.
*/
class ServiceResetterSubscriber implements EventSubscriberInterface
{
protected ResetInterface $servicesResetter;
public function __construct(ResetInterface $servicesResetter)
{
$this->servicesResetter = $servicesResetter;
}
public function resetServices(): void
{
$this->servicesResetter->reset();
}
public static function getSubscribedEvents(): array
{
return [
WorkerMessageFailedEvent::class => ['resetServices', 10],
];
}
}
Register your service with the right argument:
App\EventSubscriber\ServiceResetterSubscriber:
arguments: ['#services_resetter']
By the way without this (and without buffer limit) your app will leak and no emails will be sent ever.
Another trick:
Make sure that your message implements \JsonSerializable to get the message content in your logs, because messenger uses his monolog directly and its context serializer wish use json_encode for seriliazation.
That's why we need to customize their JSON representation when encoded is done with json_encode.
Using a saga, given an event EventA, saga starts, it sends a command (or many).
How can we make sure that the command is sent successfully then actual logic in other micro-service did not throw, etc.
Let's have an example of email saga:
When a user register, we create a User Aggregate which publishes UserRegisteredEvent, a saga will be created and this saga is responsible to make sure that registration email is sent to user (email may contain a verification key, welcome message, etc).
Should we use :
commandGateway.sendAndWait with a try/catch -> does it scale?
commandGateway.send and use a deadline and use some kind of "fail event" like SendEmailFailedEvent -> requires to associate a "token" for commands so can associate the "associationProperty" with the correct saga
that sent SendRegistrationEmailCommand
commandGateway.send(...).handle(...) -> in handle can we reference eventGateway/commandGateway that were in MyEmailSaga?
If error we send an event? Or can we modify/call a method from the saga instance we had. If no error then other service have sent an event like "RegistrationEmailSentEvent" so saga will end.
use deadline because we just use "send" and do not handle the eventual error of the command which may have failed to be sent (other service is down, etc)
something else?
Or a combination of all?
How to handle errors below? (use deadline or .handle(...) or other)
Errors could be:
command has no handlers (no service up, etc)
command was handled but exception is raised in other service and no event is sent (no try/catch in other service)
command was handled, exception raised and caught, other service publish an event to notify it failed to send email (saga will receive event and do appropriate action depending on event type and data provided -> maybe email is wrong or does not exist so no need to retry)
other errors I missed?
#Saga
public class MyEmailSaga {
#Autowired
transient CommandGateway commandGateway;
#Autowired
transient EventGateway eventGateway;
#Autowired
transient SomeService someService;
String id;
SomeData state;
/** count retry times we send email so can apply logic on it */
int sendRetryCount;
#StartSaga
#SagaEventHandler(associationProperty = "id")
public void on(UserRegisteredEvent event) {
id = event.getApplicationId();
//state = event........
// what are the possibilities here?
// Can we use sendAndWait but it does not scale very well, right?
commandGateway.send(new SendRegistrationEmailCommand(...));
// Is deadline good since we do not handle the "send" of the command
}
// Use a #DeadlineHandler to retry ?
#DeadlineHandler(deadlineName = "retry_send_registration_email")
fun on() {
// resend command and re-schedule a deadline, etc
}
#EndSaga
#SagaEventHandler(associationProperty = "id")
public void on(RegistrationEmailSentEvent event) {
}
}
EDIT (after accepted answer):
Mainly two options (Sorry but kotlin code below):
First option
commandGateway.send(SendRegistrationEmailCommand(...))
.handle({ t, result ->
if (t != null) {
// send event (could be caught be the same saga eventually) or send command or both
}else{
// send event (could be caught be the same saga eventually) or send command or both
}
})
// If not use handle(...) then you can use thenApply as well
.thenApply { eventGateway.publish(SomeSuccessfulEvent(...)) }
.thenApply { commandGateway.send(SomeSuccessfulSendOnSuccessCommand) }
2nd option:
Use a deadline to make sure that saga do something if SendRegistrationEmailCommand failed and you did not receive any events on the failure (when you do not handle the command sent).
Can of course use deadline for other purposes.
When the SendRegistrationEmailCommand was received successfully, the receiver will publish an event so the saga will be notified and act on it.
Could be an RegistrationEmailSentEvent or RegistrationEmailSendFailedEvent.
Summary:
It seems that it is best to use handle() only if the command failed to be sent or receiver has thrown an unexpected exception, if so then publish an event for the saga to act on it.
In case of success, the receiver should publish the event, saga will listen for it (and eventually register a deadline just in case); Receiver may also send event to notify of error and do not throw, saga will also listen to this event.
ideally, you would use the asynchronous options to deal with errors. This would either be commandGateway.send(command) or commandGateway.send(command).thenApply(). If the failure are businesslogic related, then it may make sense to emit events on these failures. A plain gateway.send(command) then makes sense; the Saga can react on the events returned as a result. Otherwise, you will have to deal with the result of the command.
Whether you need to use sendAndWait or just send().then... depends on the activity you need to do when it fails. Unfortunately, when dealing with results asynchronously, you cannot safely modify the state of the Saga anymore. Axon may have persisted the state of the saga already, causing these changes to go lost. sendAndWait resolves that. Scalability is not often an issue, because different Sagas can be executed in parallel, depending on your processor configuration.
The Axon team is currently looking at possible APIs that would allow for safe asynchronous execution of logic in Sagas, while still keeping guarantees about thread safety and state persistence.
Is it neccessary to call this line
Session.lookupSession(is).logon();
in this code
socketInitiator.start();
SessionID sessionId = socketInitiator.getSessions().get(0);
Session.lookupSession(id).logon();
while (!Session.lookupSession(id).isLoggedOn()) {
System.out.println("Waiting for login success");
Thread.sleep(500);
}
what is its purpose, as when I omit it, it still gets by the while loop.
EDIT_________________
I was using this in a unit test
socketInitiator.start();
SessionID sessionId = socketInitiator.getSessions().get(0);
Session.lookupSession(id).logon();
while (!Session.lookupSession(id).isLoggedOn()) {
System.out.println("Waiting for login success");
Thread.sleep(500);
}
System.out.println("Logged In...booking SingleOrder from session: " + sessionId);
//check that the party receives the fix message
assertTrue(isBookSingleOrderReceivedFromFixInbound(sessionId));
I have no idea what that function is for, or why it even exists. (I could look it up, sure, but I'm just saying that I've never had to use it.)
The start() call should cause the initiator to start attempting logins (assuming the current time is in the defined session). You shouldn't even have a while loop like this.
You should just call start(), and then do nothing. If logon succeeds, you'll see the FromApp and FromAdmin callbacks start to get triggered for incoming messages (including your logon response).
I have the following logout action:
public function logoutAction() {
Zend_Auth::getInstance()->clearIdentity();
Zend_Session::destroy();
$this->_helper->flashMessenger->addMessage(array('success' =>
_('You were successfully logged out.')));
$this->_redirect('/index/index');
}
If I don't comment out the line: Zend_Session::destroy() I get an error:
Fatal error: Uncaught exception 'Zend_Session_Exception' with message 'The session was explicitly destroyed during this request, attempting to re-start is not allowed.' in /usr/local/share/php/library/Zend/Controller/Plugin/Broker.php on line 336 Zend_Session_Exception: The session was explicitly destroyed during this request, attempting to re-start is not allowed.
I have read about this issue here and here but remain unclear on how I should proceed. Should I just not use Zend_Session::destroy()? What would be the implications and dangers of not using it, and what is the alternative?
What causes you problems is, that right after destroying the session, you are reusing it (by facilitating the FlashMessenger. If not destroying the session after logout bothers you, you could display a logout page instead of redirecting to your frontpage with a flash message.
Leaving some of your session data intact after your user logged out, might have security implications, but that depends on what you store in your session and where and how you use the data. In order to make sure, that you don't keep data, that belonged to the logged in user in your session, just use a specific session namespace for this data and call unsetNamespace() upon logout.
Zend_Auth have its own session namespace and after Zend_Auth::getInstance()->clearIdentity(); it removes it so there is no need to destroy all session nemaspaces if you use them.
Example what here happens:
// logging user
$_SESSION['Zend_Auth'] = 'logged user data';
// after Zend_Auth::getInstance()->clearIdentity();
$_SESSION['Zend_Auth'] = null;
// after Zend_Session::destroy();
session_destroy();