link shortcode

This commit is contained in:
Erik Winter 2025-01-18 15:24:45 +01:00
parent f47c5075fe
commit cd9bcf8413
12 changed files with 140 additions and 120 deletions

View File

@ -25,6 +25,8 @@ server {
{% end %}
Breakdown:
- `off` means no caching headers.
- `epoch` is no caching, ask the website itself.
- `30d` cache for 30 days.
@ -52,7 +54,7 @@ In `/etc/nginx/nginx.conf` (on Debian).
## Sources
- [www.digitalocean.com](https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-centos-7)
- [drawingablank.me](http://drawingablank.me/blog/font-mime-types-in-nginx.html)
- {{ link(title="How to Implement Browser Caching with Nginx's header Module on CentOS7", domain="www.digitalocean.com", url="https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-centos-7") }}
- {{ link(title="Font mime types in Nginx", domain="drawingablank.me", url="https://web.archive.org/web/20160430140318/http://drawingablank.me/blog/font-mime-types-in-nginx.html") }}

View File

@ -20,7 +20,10 @@ wmctrl -b add,demands_attention -r "Pomodoro"
This runs a terminal timer that counts down to zero from a specified amount of minutes and then lets the window manager draw attention to it in it's native way. In default i3 this means the border turns red, as well as the workspace indicator in the status bar.
- `wmctrl` handles the part of drawing the attention. The trick here is to make sure that attention is drawn to the right window. This is done setting the window title of the active window, the one we run the script in, to something known beforehand. This way, we can find it back later at the end of the countdown:
Breakdown of programs used:
`wmctrl` handles the part of drawing the attention. The trick here is to make sure that attention is drawn to the right window. This is done setting the window title of the active window, the one we run the script in, to something known beforehand. This way, we can find it back later at the end of the countdown:
- `-N "Pomodoro"` sets the title of the window to "Pomodoro".
- `-r :ACTIVE:` selects the currently active window.
@ -37,11 +40,11 @@ After the countdown, we let wmctrl draw the attention:
## Sources
- [en.wikipedia.org](https://en.wikipedia.org/wiki/Pomodoro_Technique)
- [gitlab.com](https://gitlab.com/moritz-weber/i3-pomodoro)
- [github.com](https://github.com/i3/i3status)
- [github.com](https://github.com/vivien/i3blocks)
- [linux.die.net](https://linux.die.net/man/1/wmctrl)
- [github.com](https://github.com/trehn/termdown)
- [askubuntu.com](https://askubuntu.com/questions/40463/is-there-any-way-to-initiate-urgent-animation-of-an-icon-on-the-unity-launcher)
- {{ link(title="Pomodoro Technique", domain="en.wikipedia.org", url="https://en.wikipedia.org/wiki/Pomodoro_Technique") }}
- {{ link(title="i3-pomodoro", domain="gitlab.com", url="https://gitlab.com/moritz-weber/i3-pomodoro") }}
- {{ link(title="i3status", domain="github.com", url="https://github.com/i3/i3status") }}
- {{ link(title="i3blocks", domain="github.com", url="https://github.com/vivien/i3blocks") }}
- {{ link(title="wmctrl(1) - Linux man page", domain="linux.die.net", url="https://linux.die.net/man/1/wmctrl") }}
- {{ link(title="termdown", domain="github.com", url="https://github.com/trehn/termdown") }}
- {{ link(title='Is there any way to initiate "urgent animation" of an icon on the Unity launcher from command line?', domain="askubuntu.com", url="https://askubuntu.com/questions/40463/is-there-any-way-to-initiate-urgent-animation-of-an-icon-on-the-unity-launcher") }}

View File

@ -5,7 +5,7 @@ date = 2020-04-17
`iota` is a helpful way to enumerate constants in Go:
```bash
{% code() %}
const (
c0 = iota
c1
@ -15,7 +15,7 @@ const (
func main() {
fmt.Println(c0, c1, c2) // "0 1 2"
}
```
{% end %}
But it is more flexible than just defining a constant to be an integer. According to the specification:
@ -25,7 +25,7 @@ So we are allowed to use expressions and conversions on the right hand side of t
However, although less seen, conversions can be pretty useful as well:
```bash
{% code() %}
type Priority string
const (
@ -35,7 +35,7 @@ const (
P3 // "P3"
...
)
```
{% end %}
It is not possible to use `strconv` functions in the `const` block because, well, they're functions. According to the specification:
@ -47,7 +47,7 @@ And that rule is:
The first 128 characters of UTF-8 are the same as the ASCII characters, prefixed with a `0`. In ASCII the characters 0 to 9 are encoded sequentially from 48 until 57, so `string(49)` converts to "1". The letters of the alphabet are encoded sequentially as well, so a range of constants representing grades from A to F could be declared in the same fashion:
```go
{% code() %}
type Grade string
const (
@ -55,14 +55,14 @@ const (
B
C
)
```
{% end %}
## Sources
- [golang.org](https://golang.org/ref/spec#Constants)
- [golang.org](https://golang.org/doc/effective_go.html#constants)
- [golang.org](https://golang.org/ref/spec#Conversions)
- [golang.org](https://golang.org/ref/spec#Conversions_to_and_from_a_string_type)
- [en.wikipedia.org](https://en.wikipedia.org/wiki/UTF-8)
- [en.wikipedia.org](https://en.wikipedia.org/wiki/ASCII#Printable_characters)
- {{ link(title="The Go Programming Language Specification - Constants", domain="go.dev", url="https://go.dev/ref/spec#Constants") }}
- {{ link(title="Effective Go - Constants", domain="go.dev", url="https://go.dev/doc/effective_go#constants")}}
- {{ link(title="The Go Programming Language Specification - Conversions", domain="go.dev", url="https://go.dev/ref/spec#Conversions") }}
- {{ link(title="The Go Programming Language Specification - Conversions to and from a string type", domain="go.dev", url="https://go.dev/ref/spec#Conversions_to_and_from_a_string_type") }}
- {{ link(title="UTF-8", domain="en.wikipedia.org", url="https://en.wikipedia.org/wiki/UTF-8") }}
- {{ link(title="ASCII", domain="en.wikipedia.org", url="https://en.wikipedia.org/wiki/ASCII#Printable_characters") }}

View File

@ -35,6 +35,6 @@ fg
## Sources
- [stackoverflow.com](https://stackoverflow.com/questions/690266/why-cant-i-use-job-control-in-a-bash-script)
- [stackoverflow.com](https://stackoverflow.com/questions/16542372/shell-script-check-mongod-server-is-running#16546193)
- {{ link(title="Why can't I use job control in a bash script?", domain="stackoverflow.com", url="https://stackoverflow.com/questions/690266/why-cant-i-use-job-control-in-a-bash-script") }}
- {{ link(title="shell script - check mongod server is running", domain="stackoverflow.com", url="https://stackoverflow.com/questions/16542372/shell-script-check-mongod-server-is-running#16546193") }}

View File

@ -1,13 +1,15 @@
+++
title = "LDAP basics for go developers"
date = 2020-04-05
[extra]
add_toc = true
+++
Recently I needed to prepare a Go application to accept LDAP as a form of authentication. Knowing absolutely nothing about LDAP, I researched the topic a bit first and I thought it would be helpful to summarize my findings so far.
Recently I needed to prepare a Go application to accept [LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) as a form of authentication. Knowing absolutely nothing about LDAP, I researched the topic a bit first and I thought it would be helpful to summarize my findings so far.
## Minimal LDAP background
If you are like me, then you know that LDAP is used for authentication and authorization but not much more. As it turns out, you can do a lot more with it than just store users and permissions. One can put the whole company inventory in it. In fact, I think it is best to view an LDAP server as a kind of weird database. The weird part is dat the data is not stored in tables, like in an SQL database, but in a tree.
If you are like me, then you know that LDAP is used for authentication and authorization but not much more. As it turns out, you can do a lot more with it than just store users and permissions. One can catalog the whole company inventory with it. In fact, I think it is best to view an LDAP server as a kind of weird database. The weird part is dat the data is not stored in tables, like in an SQL database, but in a tree.
Like a database, you cannot go out and just fire some queries at it. You have to know the schema first.
@ -21,9 +23,9 @@ Every entry in the tree has at least three components:
The distinguished name is the unique name and the location of the entry in the tree. For instance:
```
{% code() %}
cn=admin,dc=example,dc=org
```
{% end %}
could be the DN of the administrator of the example.org company. It is a list of comma separated key-value pairs with the most specific pair (`cn=admin`) on the left and the most common one, the top of the tree, on the right (`dc=org`).
@ -31,33 +33,38 @@ The `cn` and `dn` describe the type of the value. `cn` means 'common name', `dc`
The complete entry for this administrator coulde be:
```
{% code() %}
dn: cn=admin,dc=example,dc=org
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9ZGdKR1g1YTBKQ2twZkZLY1J5cHB0LzYwZmMwVWNReW4=
```
{% end %}
## Binding
LDAP does not really use the term 'authentication'. Instead one speaks of 'binding' a user. This binding is done to a BindDN, the distinguished name of a branch in the tree. Subsequent requests will be performed in the scope of that branch. That is, this user will only be able to 'see' the subbranches and leave nodes of this BindDN.
Trying it out on the command line
## Trying it out on the command line
LDAP servers require some work to setup. For the purposes of just testing things out, there are free online servers that kind people have set up and maintain. But a better solution is to find a good Docker image and run things on your local machine. The public servers will not let you modify data, for obvious reasons. The `osixia/openldap` worked for me:
```bash
docker run -p 389:389 -p 636:636 osixia/openldap
```
{% code() %}
$ docker run -p 389:389 -p 636:636 osixia/openldap
{% end %}
Port `389` is a plain `ldap://` connection, port `636` is used for a secure `ldaps://` one.
This image has a minimal set of data in it. Let's see what it contains by running a search:
```bash
$ ldapsearch -x -H ldap://localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
```
{% code() %}
$ ldapsearch -x -H ldap://localhost \
-b dc=example,dc=org -D "cn=admin,dc=example,dc=org" \
-w admin
{% end %}
Breakdown:
- `-x` to use simple authentication and no SASL
- `-H ldap://localhost` to point the program to the uri of our server
@ -67,7 +74,7 @@ $ ldapsearch -x -H ldap://localhost -b dc=example,dc=org -D "cn=admin,dc=example
The result should be something like this:
```
{% code() %}
# extended LDIF
#
# LDAPv3
@ -98,39 +105,43 @@ result: 0 Success
# numResponses: 3
# numEntries: 2
```
{% end %}
We see that we have one organization and one admin user in that organization.
Let's try to add a user. First create a file with the specifics of this new user:
```
{% code() %}
# ldapentry
dn: cn=john.doe,dc=example,dc=org
objectClass: person
cn: John Doe
sn: john.doe
description: just some guy
```
{% end %}
Then add it:
```bas
$ ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=org" -w admin -f ldapentry
{% code() %}
$ ldapadd -x -H ldap://localhost \
-D "cn=admin,dc=example,dc=org" \
-w admin -f ldapentry
adding new entry "cn=john.doe,dc=example,dc=org"
```
{% end %}
Now we must set the password:
```bash
ldappasswd -s welcome123 -w admin -D "cn=admin,dc=example,dc=org" -x "cn=john.doe,dc=example,dc=org"
```
{% code() %}
$ ldappasswd -s welcome123 -w admin \
-D "cn=admin,dc=example,dc=org" \
-x "cn=john.doe,dc=example,dc=org"
{% end %}
`-s welcome123` sets the password to welcome123.
Check that it was added:
```
{% code() %}
$ ldapsearch -x -H ldap://localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
# extended LDIF
#
@ -171,13 +182,15 @@ result: 0 Success
# numResponses: 4
# numEntries: 3
```
{% end %}
Now, let's see if we can authenticate as this new user and see ourselves:
```
$ ldapsearch -x -H ldap://localhost -b "cn=john.doe,dc=example,dc=org" -D "cn=john.doe,dc=example
,dc=org" -w welcome123
{% code() %}
$ ldapsearch -x -H ldap://localhost \
-b "cn=john.doe,dc=example,dc=org" \
-D "cn=john.doe,dc=example,dc=org" \
-w welcome123
# extended LDIF
#
# LDAPv3
@ -201,7 +214,7 @@ result: 0 Success
# numResponses: 2
# numEntries: 1
```
{% end %}
Succes!
@ -217,7 +230,7 @@ For Go, there a package that can do the heavy lifting for us, called `go-ldap`.
The package has example code in the `README.md` that follows exactly these steps. Adjusting for the values we used above, we get:
```go
{% codedetails(summary="Click to expand") %}
# main.go
package main
@ -229,7 +242,6 @@ import (
)
func main() {
username := "cn=admin,dc=example,dc=org"
password := "admin"
@ -251,11 +263,9 @@ func main() {
fmt.Println("searching user...")
searchRequest := ldap.NewSearchRequest(
bindusername,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf("(&(objectClass=person))"),
[]string{"dn"},
nil,
bindusername, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
0, 0, false, fmt.Sprintf("(&(objectClass=person))"),
[]string{"dn"}, nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
@ -279,11 +289,11 @@ func main() {
log.Fatal(err)
}
}
```
{% end %}
Running it:
```bash
{% code() %}
$ go run main.go
connect..
binding binduser..
@ -291,18 +301,17 @@ searching user...
&{Entries:[0xc0001086c0] Referrals:[] Controls:[]}
binding user...
switching back..
```
{% end %}
Success again!
## Sources
- [ldap.com](https://ldap.com/basic-ldap-concepts/)
- [stackoverflow.com](https://stackoverflow.com/questions/18756688/what-are-cn-ou-dc-in-an-ldap-search)
- {{ link(title="Basic LDAP Concepts", domain="ldap.com", domain="ldap.com", url="https://ldap.com/basic-ldap-concepts/") }}
- {{ link(title="What are CN, OU, DC in an LDAP search?", domain="stackoverflow.com", url="https://stackoverflow.com/questions/18756688/what-are-cn-ou-dc-in-an-ldap-search") }}
- `man ldapsearch`, `man ldapadd` and `man ldappasswd`
- [www.forumsys.com](http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/)
- [serverfault.com](https://serverfault.com/questions/514870/how-do-i-authenticate-with-ldap-via-the-command-line)
- [github.com](https://github.com/osixia/docker-openldap)
- www.thegeekstuff.com
- [pkg.go.dev](https://pkg.go.dev/github.com/go-ldap/ldap?tab=doc)
- {{ link(title="Online LDAP Test Server", domain="www.forumsys.com", url="http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/") }}
- {{ link(title="How do I authenticate with LDAP via the command line?", domain="serverfault.com", url="https://serverfault.com/questions/514870/how-do-i-authenticate-with-ldap-via-the-command-line") }}
- {{ link(title="osixia/openldap", domain="github.com", url="https://github.com/osixia/docker-openldap") }}
- {{ link(title="Basic LDAP v3 functionality for the GO programming language", domain="pkg.go.dev", url="https://pkg.go.dev/github.com/go-ldap/ldap?tab=doc") }}

View File

@ -10,6 +10,8 @@ $ reflex -r '\.go$' -- \
sh -c 'clear && go test -v ./web/model --run TestEvent'
{% end %}
Breakdown:
- **reflex** is a small utilty that watches for changes on the file system.
- **-r** indiates that it should only watch changes in files that satisfy the following regex pattern.
- **'\.go$'** the regex tells to only watch changes in go files.
@ -26,9 +28,9 @@ Remember, **reflex** is only triggered by changes on the filesystem. After enter
## Sources
- [github.com](https://github.com/cespare/reflex)
- [unix.stackexchange.com](https://unix.stackexchange.com/questions/11376/what-does-double-dash-mean)
- {{ link(title="Reflex", domain="github.com", url="https://github.com/cespare/reflex") }}
- {{ link(title="What does '--' (double dash / double hyphen) mean?", domain="unix.stackexchange.com", url="https://unix.stackexchange.com/questions/11376/what-does-double-dash-mean") }}
- **man sh**
- [blog.alexellis.io](https://blog.alexellis.io/golang-writing-unit-tests/)
- [golang.org](https://golang.org/cmd/go/#hdr-Testing_flags)
- {{ link(title="Golang basics - writing unit tests", domain="blog.alexellis.io", url="https://blog.alexellis.io/golang-writing-unit-tests/") }}
- {{ link(title="go command - Testing flags", domain="pkg.go.dev", url="https://pkg.go.dev/cmd/go#hdr-Testing_flags") }}

View File

@ -3,13 +3,13 @@ title = "Shared environment variables for make, bash and docker"
date = 2020-01-07
+++
It is possible to define a set of variables and share them in Make, Bash and the Docker containers that are orchestrated by `docker-compose`.
It is possible to define a set of variables and share them in `make`, `bash` and the Docker containers that are orchestrated by `docker-compose`.
Docker-compose can use an `.env` file to substitute variables in a `docker-compose.yml` file in the same directory. In this docker-compose.yml they can be exported to the containers.
Incuding this `.env` file in your `Makefile` makes hem available there as well, but they are not automatically exported to the Bash shells that are spawned by `make` to execute the targets. This can be changed by adding the `.EXPORTALLVARIABLES:` target to your `Makefile`.
Incuding this `.env` file in your `Makefile` makes hem available there as well, but they are not automatically exported to the `bash` shells that are spawned by `make` to execute the targets. This can be changed by adding the `.EXPORTALLVARIABLES:` target to your `Makefile`.
`.env`:
An example that covers all areas is this `.env` file:
{% code() %}
VAR1=this
@ -17,7 +17,7 @@ VAR2=that
VAR3=those
{% end %}
`Makefile`:
With a `Makefile`:
{% code() %}
include .env
@ -30,7 +30,7 @@ task:
@docker-compose up
{% end %}
`docker-compose.yml`:
Together with this `docker-compose.yml`:
{% code() %}
...
@ -42,6 +42,6 @@ app:
## Sources
- [vsupalov.com](https://vsupalov.com/docker-arg-env-variable-guide/#the-dot-env-file-env)
- [www.gnu.org](https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets)
- {{ link(title="Docker ARG, ENV and .env - a Complete Guide", domain="vsupalov.com", url="https://vsupalov.com/docker-arg-env-variable-guide/#the-dot-env-file-env") }}
- {{ link(title="4.9 Special Built-in Target Names", domain="www.gnu.org", url="https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets") }}

View File

@ -6,7 +6,7 @@ title = "About"
My name is Erik, and I am a Dutch software developer. Go is my language of choice, as one can easily gather from the posts on this site. At work I like to program in Go, outside of work I like to program in Go.
When I am not programming... I dream of programming in Go. Nah, just kidding, I mostly do the same things as everyone else. Listen to music, watch movies, etc. I also have written some short stories and other fiction. If you can understand Dutch, you can read them at [vrijkorteverhalen.nl](https://vrijkorteverhalen.nl) 🇳🇱.
When I am not programming... I dream of programming in Go. Nah, just kidding, I mostly do the same things as everyone else. Listen to music, watch movies, etc. I also have written some short stories and other fiction. If you understand Dutch, you can read them at [vrijkorteverhalen.nl](https://vrijkorteverhalen.nl) 🇳🇱.
## Find me elsewhere

View File

@ -85,8 +85,9 @@ pre code {
blockquote {
font-style: italic;
border: thin solid black;
//border: thin solid black;
padding: 1rem;
margin: 1rem 0;
p { margin: 0; }
}

View File

@ -7,6 +7,7 @@
{% set subsections = section.subsections | sort | reverse %}
{% for s in subsections %}
{% set ss = get_section(path=s) %}
{% if ss.title != "About" %}
<h2>{{ ss.title }}</h2>
{% set ps = ss.pages | sort(attribute="date") | reverse %}
<ul>
@ -18,5 +19,6 @@
</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
{% endblock content %}

View File

@ -0,0 +1 @@
<a href={{ url }}>{{ title }}</a> - <em>{{ domain }}</em>