Skip to content
 
 

Repository files navigation

B3 micronomy

A middleware and alternative web GUI to access Maconomy. It is mainly intended as a programming exercise but is actually somewhat easier to work with than the main Maconomy GUI.

Usage

Connecting

Point you browser at https://micronomy.init.se/ and log in with your B3 Maconomy credentials, or with the "Logga in med Microsoft" button if single sign-on is available - see Single sign-on below. Both methods work side by side.

To run it locally you can either install Rakudo and the required modules or make sure you have a working Docker installation and build and run the Dockerfile. The browser will complain about the fake certificate in use when running locally but that's expected. Just running

./micronomy.sh docker

could be enough.

Technically there's nothing stopping you from connecting the micronomy service to some other Maconomy backend but only the B3 Maconomy has been tested.

Hours

Time is expected to be filled in as decimal hours; eg. "an hour and a half" should be entered as 1.5. The sums shown beneath the time records are read from the API; no time calculations are done in Micronomy.

Weeks

To directly switch to a specific week you can add ?date=YYYY-MM-DD in the browsers address field. Note that weeks on month borders will be divided into A and B as in Maconomy.

Projects

Adding or removing the projects shown currently has to be done in Maconomy. Note though, that you can specify in Maconomy that the same records should be shown on consecutive weeks too.

Keyboard shortcuts

Hitting enter while entering times is equivalent to pressing the "Spara" button; ie. it saves the entered times into the database. To switch to next or previous week you can press the appropriate buttons or Ctrl-Right or Ctrl-Left respectively. The arrow keys can be used to navigate between the time fields. Hitting Escape will unfocus any time field and Ctrl-Down will re-focus the same field.

Submitting

When a week is completely filled in, it should be submitted by pressing the "Avlämna" button. As in Maconomy, there's nothing stopping you from re-submitting an already submitted week but if you change an already billed week, the changes will probably be ignored by the billing system. So don't do that without consulting with you manager first.

Command-line client

For scripting or terminal-only use there's also a CLI client in cli/ that talks to the Maconomy iAccess API directly (it does not go through the Micronomy web service). See cli/README.md for build instructions and usage, but in short:

micronomy login
micronomy get
micronomy set --row 0 --day 1 --hours 8.5
micronomy submit

Contributing

If you find any bugs or even want to fix one you can go to https://github.com/krakan/micronomy/issues/. If the bug you've found isn't there already, please report a new issue. To contribute code you'll have to fork the code to you own Github account and commit your code there and then make a pull request against the main repository.

You're also welcome to add some of the missing features already reported as issues. Follow the same procedure as for bugs.

Server setup

Start with eg. a basic Debian and then run the following:

sudo apt update
sudo apt install -y libssl-dev git perl curl rsync certbot nginx tmux

curl https://rakubrew.org/install-on-perl.sh | bash
eval "$($HOME/.rakubrew/bin/rakubrew init Bash)"

rakubrew download
rakubrew build zef

zef install --serial Cro::WebApp URI::Encode Digest::MD5 MIME::Base64

Basing this on Debian is of course optional - any platform that can run rakudo should work but then the above installation commands will be different.

After the server is set up, clone this repo to it and run

export MICRONOMY_PORT=443
export MICRONOMY_HOST=0.0.0.0
raku -I lib service.raku

There is also a script micronomy.sh that handles Let's Encrypt renewal and forwards the service's log output to syslog (tagged micronomy, so eg. grep micronomy: /var/log/syslog). You'll most likely need to customize it before using it.

To split that output into its own log file instead of leaving it mixed into the general syslog, install the provided rsyslog and logrotate config on the server:

sudo cp resources/rsyslog-micronomy.conf /etc/rsyslog.d/10-micronomy.conf
sudo cp resources/logrotate-micronomy /etc/logrotate.d/micronomy
sudo systemctl restart rsyslog

This routes messages tagged micronomy to /var/log/micronomy.log (and stops them from also going to the general syslog), with weekly rotation keeping 8 compressed generations.

Unfortunately, there seems to be some problem with SSL that under some circumstances makes HTTPS connections hang indefinitely. In that case one can use the resources/nginx.conf file to let Nginx handle the SSL termination and then run Micronomy on an unprivileged port - eg.:

sudo sed -Ei "s:^( *ssl_certificate) .*:\1 $MICRONOMY_TLS_CERT;:" resources/nginx.conf
sudo sed -Ei "s:^( *ssl_certificate_key) .*:\1 $MICRONOMY_TLS_KEY;:" resources/nginx.conf
sudo cp resources/nginx.conf /etc/nginx/sites-enabled/default
sudo systemctl restart nginx
./micronomy.sh --port 8080

Single sign-on (OIDC)

If the Maconomy tenant has an OpenID Connect provider configured - B3's has Azure AD (Entra ID) - the login page offers a "Logga in med Microsoft" button alongside the password form. Micronomy asks Maconomy what it supports on every login page (cached for an hour) and only shows the button when the x-oidc-code scheme is actually advertised, so a tenant without SSO, or one where it is temporarily unavailable, simply gets the password form. The demo/demo account is unaffected.

Micronomy never handles a client secret and never talks to the identity provider's token endpoint. It redirects the browser to the provider, receives an authorization code back, and hands that code to Maconomy, which performs the exchange itself and returns the same Maconomy-Reconnect token a password login would have produced. In outline:

  1. anonymous GET maconomy-api/auth/b3 with Accept: application/vnd.deltek.maconomy.authentication+json returns the available schemes and openIDProviders[0].links.authorization-url.template
  2. {redirect-uri} in that template is replaced with Micronomy's own callback URL, and the browser is sent there with a random state
  3. the provider redirects back to the callback with ?code=...&state=...; the state has to match the oidcState cookie set in step 2
  4. GET maconomy-api/auth/b3 with Authorization: X-OIDC-Code <base64("<redirect-uri>:code")> - note the angle brackets, which is how Maconomy finds the separator in a string that contains colons of its own - returns the session token

Configuration

The callback URL must match a redirect URI registered with the identity provider byte for byte. Micronomy derives it from the request Host (assuming https unless X-Forwarded-Proto says otherwise, since Nginx terminates TLS), which works for a plain deployment, but set it explicitly when anything in front of the service makes that guess wrong:

export MICRONOMY_CALLBACK_URL=https://micronomy.init.se/login/oidc/callback

That same URL has to be added to the app registration's allowed redirect URIs on the provider side, and Maconomy has to be able to map the verified identity to a Maconomy employee, or the exchange in step 4 will fail. Both are administrative tasks outside this repository.

The session cookie set by an SSO login is SameSite=Lax rather than the password login's Strict: the browser arrives at the callback from the provider, across sites, and a Strict cookie would be withheld from the redirect that follows. Lax still keeps the cookie off every cross-site POST, and every state change in Micronomy is a POST.

The notes from working the protocol out - including what the web client's own JavaScript does, and the open questions for B3 IT - are in git history: git show 845ef9c:sso-oidc-investigation.md and git show 845ef9c:sso-oidc-todo.md.

Running as a service

Sample systemd unit files are provided to run Micronomy unattended:

  • micronomy.service runs micronomy.sh --port 8080 and restarts it automatically.
  • memfree.service runs memfree.sh, which monitors free memory and forces garbage collection (or kills raku outright) if it drops too low; this works around a memory leak in long-running Raku processes.
  • wait-for-restart.service runs micronomy.sh wait-for-restart, a small helper that lets Nginx return a friendly "please wait" response while the main process is restarting instead of a connection error.

Copy the ones you need to /etc/systemd/system/, adjust the paths and User to match your setup, then enable them with eg. sudo systemctl enable --now micronomy.service.

About

An alternative client to access Maconomy

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages