auth: handle edge case when fetching users from meta
Refactor config loading and server initialization
As is, LoadConfig() does some things that are not strictly related to
the configuration, such as parsing command line arguments. This has led
to a proliferation of different ways to load the config based on various
needs and also prevents tools that need a config but are not services to
use custom command line arguments.
This commit aims to decouple config loading from everything else and
do nothing but loading the config files.
On a high level, this commit:
- renames server.NewServer() to server.New()
- moves config.Debug and config.Addr into the server package
- moves crypto.InitCrypto() call into server.New()
- moves command line parsing into server.New(), using passed-in values
rather than os.Args
The only changes required for services would be changing
cfg := config.LoadConfig(":5100")
server := server.NewServer("meta.sr.ht", cfg)
to
cfg := config.LoadConfig()
server := server.New("meta.sr.ht", ":5100", cfg, os.Args)
All other tools will be switched to just LoadConfig() and, optionally, a
call to crypto.InitCrypto(). I managed to completely remove some global
state (addr) and at least make the rest private, so that users are
forced to use the designated functions.
The config module gained support for custom FS implementation, mainly
for testing.
Don't prevent suspended users from authenticating
With cookies or internal auth. The frontends already prevent users from
accessing services while suspended, and there are some complications if
we don't let the frontends access the backends at all if the
authenticated user is suspended.
auth: remove legacy OAuth support
auth/bearer: log username associated with expired token
auth: fix remote IP determination for audit log
This is probably isolated to dev or other small environments, but I had
two issues with the remote IP determination, breaking the audit log
display in my dev env after fairly standard usage.
The gist is that the audit log is designed to contain clean IP addresses
only. However, the algorithm starts out with `r.RemoteAddr`, which may
contain a port (usually 127.0.0.1:xxxxx). The port removal is already
performed at the beginning of the function, so simply re-use the result
of this.
Furthermore, the initial value (containing the port leading to breakage)
landed in the audit log because I was using a private IP (it's my dev
evn). We correctly trust private IPs, but that means if no public IP
ever shows up in the X-Forwarded-For header, the last private IP was the
one that actually made the request.
I am not entirely sure why this showed up now. I already had a bunch of
oder audit log entries that had the correct private-but-not-localhost
addresses. But in the current state, e.g. simply updating my profile
would cause the bad IP:port notation to be written to the audit log.
auth: fix middleware tests
They got broken with 6eae2199 because the tests cannot use
`config.LoadConfig`, so the list of internal IP nets never gets
populated.
webhooks: implement internal webhook users
AUTH_INTERNAL requests previously could not register webhooks. This
commit adds the necessary changes to allow for this.
all: pass errors to panic, not strings
GraphQL's recovery middleware can't handle strings so it just logs a
very not useful <nil>
auth: use config.IsInternalIP
auth: reduce scope of user_type
auth: grant scoped access to anon internal auth
Internal auth is granted access to everything, whereas anonymous
internal auth is pretty restricted. This is mostly to avoid accidentally
hitting resolvers that require a logged-in user, however. Given that all
anon internal use cases are hard-coded and tested, this seems like a
pretty low risk. Allowing this will have the huge benefit of making much
more information available to anon internal queries, which will unlock
removing a bunch of awkward work-arounds we put in place.
Note, however, that this is also a work-around. It saves us from adding
yet more work-arounds to the GQL schema, and in the meantime a redesign
of the schema (especially the directives) is being worked on.
auth/middleware: fix user_type on new users
auth/middleware: convert user types to uppercase
auth: add Grants.IsSubset
This is a little bit hacky. Previously DecodeGrants would only store the
list of grants associated with the current service. This minimizes API
breakage by storing all grants as $service/$grant in the map key and
stores the local service name in the grant object, and updates
Grants.Has() to accept "$grant" and infer that it refers to a local
service or accept the fully qualified "$service/$grant" to test against
grants for any service -- which IsSubset makes use of to test that one
Grant object is a subset of another with respect to all services it has
grants for.
server: use routing groups
Instead of hardcoding some exceptions in the auth middleware, use a
different routing group for routes that do not require auth. Makes the
auth middleware more generic and also removes a lot of unneccessary
middleware processing from routes that don't need it.
For now, the added group is not accessible from outside the module, but
if the need arises, this might be an option.
auth: add auth.IPAddress
With support for X-Forwarded-For
auth/middleware: set WWW-Authenticate header field
See RFC 6750 section 3.
client: rename Execute to Do
583d0b1bcb08 ("client/graphql: handle GraphQL errors") changed
Execute behavior by wrapping the result into a struct with "data"
and "errors" fields. This is a breaking change, but it's hard to
spot when upgrading core-go because it won't cause a compilation
error.
Rename Execute to Do to break the build and force callers to update
accordingly.
auth: add RequireMiddleware
Same as Middleware, but requires auth for all requests. Will be
useful to drop hacks from pages.sr.ht.