Tuesday, March 31, 2020

flask basic auth super simple

I wrote a super simple basic auth using flask app that does all the authentication in the app side.

https://gitlab.com/rikijpn/flask_simple_basic_auth

Don't ask me why... But hey, it works.

Using microsoft graph API to book things in outlook

Quick notice

I hate microsoft. Soooo much. And its API even more. I hated everything about using it, and having to read its very hard to understand documentation.
But it's the lesser evil to actually having to use ms outlook to book meeting rooms in an environment non ms free. The real solution is to get rid of microsoft and everything microsoft in your office.

Purpose

My office has these meeting rooms, which are always occupied. And it's very hard to make a reservation. I hate ms outlook too much to have to do this every day manually, so I checked out the ms "graph API" (in case you wonder, it's not to make "graphs", it's just the stupid name they use for their office API).
Now I can get all the meeting rooms I need daily for all my team without having to move a finger.

Code

The actual script I use is here: https://gitlab.com/rikijpn/ugly_ms_outlook_appointment_taker
I'm obviously removing all the tokens though.
It's in python, running daily. So you can just put this in cron, so as soon as they let you book meeting rooms (like 30, 60 days after the current day's specific time) you'be able to send the appointment request.

Preparation (create an "app")


1. create app (in your azure portal)
In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations → New registration.
https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
2. in azure, select Manage → API Permissions → app (Microsoft APIs → Microsoft Graph → Delegated permissions)
Make sure you have the following permissions:
Calendars.ReadWrite
User.Read
offline_access

3. in azure, select Manage → Authentication → "Default client type" → "Treat application as public client"
4. in azure, select Manage → Authentication → "Supported account types" → "Accounts in this organizational directory only (this will probably have your company/school name here)"
5. get consent
https://login.microsoftonline.com/${tenant_id}/oauth2/v2.0/authorize?client_id=${client_id}&response_type=code&response_mode=query&state=12345&scope=offline_access%20user.read%20Calendars.ReadWrite
The "tenant_id" here is just  whatever you already have in your url when looking azure, a long senseless string, that is common through all the pages for your organization.
"client_id" will be shown in your "app"'s top/info page.
You can just ignore the rest and use it as it is.

Put this in your browser, and you'll be sent to a blank page by default. Check the URL in your browser, and you'll see there will be an "access" and "refresh" token.

Usage

And that's pretty much it. Now you are ready to do some tests.
I'm posting the test code (emacs's restclient-mode stuff) in the same gitlab repo: https://gitlab.com/rikijpn/ugly_ms_outlook_appointment_taker/-/blob/master/sample_requests.txt
In short, every time you want to use it, you'll have to use your "refresh_token" to create a new "access_token", which lasts very shortly (a couple of mins? one hour? don't remember).


One thing though, is that every time you change your password, you'll have to do get consent again:
https://login.microsoftonline.com/${tenant_id}/oauth2/v2.0/authorize?client_id=${client_id}&response_type=code&response_mode=query&state=12345&scope=offline_access%20user.read%20Calendars.ReadWrite

And update your tokens.

When you make a meeting room reservation (appointment, using the meeting room as a "resource"), you'll get a 200 status code if your auth has no issues. But that DOES NOT mean your meeting room was acknowledged, and that you got the meeting room. It just means the damn ms outlook server got  your request. The pain.
You'll get an e-mail with the approval/denial response a bit after your request is processed. I think you can also check with the API somehow.

Final thoughts

Really ugly documentation. That's how I've described pretty much all ms documentation in the past, and how I still do for everything about this "graph API" thing.
It's like, they don't really want you to be able to use it.
The token usage is frankly not bad, seems like a good (secure and clear) authorization and all, most likely thanks to its usage of OAuth2.0 and JWT.

Thursday, March 26, 2020

ssh tunnels

I love ssh tunnels.

Working in an office, with a super strict data center, they make my work so much easier.

Basically an ssh tunnel is a way to put a local port in a remote server, and vice-versa.

Scenarios it might be useful:

  1. You have a bastion/jump server that you need to connect to do EVERYTHING. It makes sense to just have one main ssh session established, and just connect with the same dynamic proxy tunnel to all the rest of the servers stepping through, without having to connect again each time.

    Situation:
    local machine TO jump server
    local machine TO jump server, jump server TO server only accessible by jump server1
    local machine TO jump server, jump server TO server only accessible by jump server2
    ...
    (above, you need to ssh to the jump server, and from then, ssh to the remote server, every time.)

    Solution:
    local machine TO jump server
    local machine ( through tunnel ) server only accessible by jump server1
    local machine ( through tunnel ) server only accessible by jump server2
    ...
    (above, you just open one session to the jump server. And then can ssh directly from your local box to the remote servers through the tunnel)
  2. You can ssh from your local machine TO a server, but not the other way around (due to firewall, being behind a router, etc)

    Situation:
    local machine TO remote server = OK
    remote  server TO local machine = NO

    Solution:
    local machine TO remote server (remote forward:9001 to localhost:22)
    remote server TO remote server port 22 (=local machine's ssh port = local machine)
  3. You want to share a port/server only accessible from the office, to a remote server. Let's say, your intra network's GIT server, to a server. Or your mail server, local printer, etc.

    Situation:
    local machine TO intra git = OK
    remote server TO intra anything = NO

    Solution:
    local machine TO remote server (remote forward RANDOM_PORT to intra git server's SSH PORT)
    remote server TO remote server's RANDOM_PORT (goes through your local box, and to intra's git server)
  4. Debugging your flask DEV env on port 5000, and your firewall doesn't let you access it directly.

    Situation:
    local machine TO remote server's port 5000 = NO
    local machine TO remote server = OK (ssh)
    remote server  TO remote server's port 5000 = OK

    Solution:
    local machine TO remote server (local forward 5000 to localhost:5000)
    local machine TO local machine's port 5000 ( = remote server's port 5000)

These are just some simple examples.
You can also kind of nest them! One ssh tunnel to another, and another... and sometimes it gives you a bit of a headache.
My .ssh/config file is huge due to this, but it beats the alternative of not being able to debug a flask development instance live with your browser, for example.


What is dynamic/local/remote forwarding?

In short:
Dynamic tunnels act as SOCKS servers. This means you can ssh connect with the nc command sending all the stream directly. When you set up dynamic forwarding for a host, your local machine dynamic forwarding port will act as a SOCKS server.

local forwarding = the port will be on your local machine, pointing to somewhere in the remote server

remote forwarding = the port will be in the remote server, pointing to somewhere on your local machine

Easy, right?

So, how to do you this?


I think you can do this in windows terminals too, and even macs. But This is GNU/Linux blog, so I'll be talking only about the ssh command and its config.

You can do all this with arguments to the ssh command, but I was never able to remember those. So I just edit my ~/.ssh/config file for all these settings, and that's the way I'll be introducing.

All settings below will be in your local machine's ~/.ssh/config.

Let's create a dynamic tunnel


Host some-jump-server.net
  # these two aren't really necessary, I just like them
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  DynamicForward 5555

So, you just "ssh some-jump-server.net" in one terminal, and keep that session open.
To access a server only accessible from the jump server, you just add that server to your ~/.ssh/config, defining it as a server that needs to go through that proxy, or you can also like create a script for the same purpose.

This is how I'd register the server:

Host some-server.my-subnet
     ProxyCommand nc -x 127.0.0.1:5555 %h %p

Then you just "ssh some-server.my-subnet". And in one ssh, you should be accessing the remote server.
You'll probably be needing an ssh agent if you plan to do this though, but that's a topic for another post.

Also, notice you don't need to add hosts one by one, you can set complete sub-domains, or just "all" with the "*" wildcard (next to the "Host" keyword). "*.my-subnet" for example, would set this dynamic proxy port for all servers you try to ssh that end with ".my-subnet".

Let's try a localforward

Local Fowards open a port in your local machine, to somewhere pointing on the remote server.
Let's use the flask development port (5000) for example, that you can only see in your server, and can't access directly from anywhere else.

Host some-server-with-my-flask-dev.my-subnet
     LocalForward 8559 localhost:5000

So, now you can just put your in local machine's browser the url http://localhost:8559/, and you'll be accessing your remote host's port 5000, yay. No need to proxy or anything, just ssh.

And, let's try a remoteforward

The last one, remote forward, opens a port in the remote server, pointing somewhere in your local machine.

Host some-server-that-needs-intra-stuff.my-subnet
  # pointing your local git server for example
  RemoteForward 5757 192.168.11.1:7999

  # or to your tiny proxy http proxy, in case you need to access intra web
  RemoteForward 8999 localhost:8888

So, if you ssh to some-server-that-needs-intra-stuff.my-subnet, you'll be able to see with "netstat -atn|grep LISTEN" for example, that the ports 5757 and 8999 are open. And they'll be pointing to your local machine's 7999 and 8888 ports respectively. In this example, they're your local git server, and http proxy. So virtually, you could be accessing the same INTRA web from a DC that shouldn't have access at all! yay! Welcome to the wonderful world of security risks as well, be careful!


In conclusion, ssh tunneling is fun. Remember you can also have multiple remote and local forwards in each host block, and you mix them as well. It can be quite a mess! But sooo damn useful.

Wednesday, March 25, 2020

using synergy to share your keyboard and mouse with another computer

What's Synergy?

An awesome program that allows you to share your mouse/keyboard over the network with another computer.
You basically need to have the "server" installed on the computer your keyboard/mouse are connected to, and a "client" to the other one.


I use this at the office, where I'm sadly forced to use ms windows, and connect it to my GNU/Linux box.
I also use it at home when I bring my office laptop sometimes, and just do all the input with my home keyboard/mouse, as I'm a happyhacking keyboard fan.

How to install

On Windows: google for "windows synergyc 1.8.8", for the windows one, and install that
On GNU/Linux Debian-family: sudo apt-get install synergy

in Debian 10

As of debian 10, synergy is an outdated package apparently. I guess it wasn't very popular...

But you can install it from the stretch's repo directly, like this:


sudo apt-get install libcrypto++6 libqt4-network libqtcore4 libqtgui4
wget http://ftp.jp.debian.org/debian/pool/main/s/synergy/synergy_1.4.16-2_amd64.deb #just find this deb file in whatever mirror you prefer
sudo dpkg -i synergy_1.4.16-2_amd64.deb 


How to setup

in ms windows (client)

Just make a "shortcut" with something like "C:\Synergy\synergyc.exe XX.XX.XX.XX"  (your server's IP)

in GNU/Linux

create a file /etc/synergy.conf with these contents:


section: screens
random_name_for_your_server_box:
random_name_for_your_client_box:
end
 
section: links
random_name_for_your_client_box:
        left = random_name_for_your_server_box
random_name_for_your_server_box:
        right  = random_name_for_your_client_box
end


You'll also need to put your "random_name_for_your_server_box" name in /etc/hosts.

How to use

1. in windows: double click the "shortcut" thing
2. in GNU/Linux, open a terminal, and type "synergys"

The client terminal should show some debug messages, like "server connected!" and stuff like that.
Just move your mouse pointer and see it go from your server screen to your client's.

I'm surprised really so few people know about this and end up buying more keyboards, or worst, using a bluetooth one just to be able to switch the input (facepalm). sshing is also super useful and all, but sometimes you use a crappy OS like ms windows in which that's just not possible, or just want to use it on its same screen.

You can also use this in a better environment, GNU/Linux with GNU/Linux.
Don't get me started about macs.