Coder Social home page Coder Social logo

qvest-digital / loginsrv Goto Github PK

View Code? Open in Web Editor NEW
1.9K 50.0 148.0 549 KB

JWT login microservice with plugable backends such as OAuth2, Google, Github, htpasswd, osiam, ..

License: MIT License

Shell 0.10% Go 98.60% HTML 1.06% Dockerfile 0.24%
jwt htpasswd service golang caddy caddyserver login oauth2 github

loginsrv's Introduction

loginsrv

loginsrv is a standalone minimalistic login server providing a JWT login for multiple login backends.

Docker Build Status Go Report Card Coverage Status Join the chat at https://gitter.im/tarent/loginsrv

** Attention: Update to v1.3.0 for Google Login Update !!!! **

Google will stop support for the Google+ APIs. So we changed loginsrv to use the standard oauth endpoints for Google login. Please update loginsrv to v1.3.0 if you are using google login.

** Attention: Since v1.3.0, pure HTTP is not supported by default **

Since v1.3.0, loginsrv sets the secure flag for the login cookie. So, if you use HTTP fo connect with the browser, e.g. for testing, you browser will ignore the cookie. Use the flag -cookie-secure=false when testing without HTTPS.

Abstract

Loginsrv provides a minimal endpoint for authentication. The login is performed against the providers and returned as a JSON Web Token (JWT). It can be used as:

  • Standalone microservice
  • Docker container
  • Golang library
  • Caddy plugin. (See caddy/README.md for details)

Supported Provider Backends

The following providers (login backends) are supported.

Questions

For questions and support please use the Gitter chat room.

Join the chat at https://gitter.im/tarent/loginsrv

Configuration and Startup

Config Options

Note for Caddy users: Not all parameters are available in Caddy. See the table for details. With Caddy, the parameter names can also be used with _ in the names, e.g. cookie_http_only.

Parameter Type Default Caddy Description
-cookie-domain string X Optional domain parameter for the cookie
-cookie-expiry string session X Expiry duration for the cookie, e.g. 2h or 3h30m
-cookie-http-only boolean true X Set the cookie with the HTTP only flag
-cookie-name string "jwt_token" X Name of the JWT cookie
-cookie-secure boolean true X Set the secure flag on the JWT cookie. (Set this to false for plain HTTP support)
-github value X OAuth config in the form: client_id=..,client_secret=..[,scope=..][,redirect_uri=..]
-google value X OAuth config in the form: client_id=..,client_secret=..[,scope=..][,redirect_uri=..]
-bitbucket value X OAuth config in the form: client_id=..,client_secret=..[,scope=..][,redirect_uri=..]
-facebook value X OAuth config in the form: client_id=..,client_secret=..[,scope=..][,redirect_uri=..]
-gitlab value X OAuth config in the form: client_id=..,client_secret=..[,scope=..,][redirect_uri=..]
-host string "localhost" - Host to listen on
-htpasswd value X Htpasswd login backend opts: file=/path/to/pwdfile
-jwt-expiry go duration 24h X Expiry duration for the JWT token, e.g. 2h or 3h30m
-jwt-secret string "random key" X Secret used to sign the JWT token. (See caddy/README.md for details.)
-jwt-secret-file string X File to load the jwt-secret from, e.g. /run/secrets/some.key. Takes precedence over jwt-secret!
-jwt-algo string "HS512" X Signing algorithm to use (ES256, ES384, ES512, RS256, RS384, RS512, HS256, HS384, HS512)
-log-level string "info" - Log level
-login-path string "/login" X Path of the login resource
-logout-url string X URL or path to redirect to after logout
-osiam value X OSIAM login backend opts: endpoint=..,client_id=..,client_secret=..
-port string "6789" - Port to listen on
-redirect boolean true X Allow dynamic overwriting of the the success by query parameter
-redirect-query-parameter string "backTo" X URL parameter for the redirect target
-redirect-check-referer boolean true X Check the referer header to ensure it matches the host header on dynamic redirects
-redirect-host-file string "" X A file containing a list of domains that redirects are allowed to, one domain per line
-simple value X Simple login backend opts: user1=password,user2=password,..
-success-url string "/" X URL to redirect to after login
-template string X An alternative template for the login form
-text-logging boolean true - Log in text format instead of JSON
-jwt-refreshes int 0 X The maximum number of JWT refreshes
-grace-period go duration 5s - Duration to wait after SIGINT/SIGTERM for existing requests. No new requests are accepted.
-user-file string X A YAML file with user specific data for the tokens. (see below for an example)
-user-endpoint string X URL of an endpoint providing user specific data for the tokens. (see below for an example)
-user-endpoint-token string X Authentication token used when communicating with the user endpoint
-user-endpoint-timeout go duration 5s X Timeout used when communicating with the user endpoint

Environment Variables

All of the above Config Options can also be applied as environment variables by using variables named this way: LOGINSRV_OPTION_NAME. So e.g. jwt-secret can be set by environment variable LOGINSRV_JWT_SECRET.

Startup Examples

The simplest way to use loginsrv is by the provided docker container. E.g. configured with the simple provider:

$ docker run -d -p 8080:8080 tarent/loginsrv -cookie-secure=false -jwt-secret my_secret -simple bob=secret

$ curl --data "username=bob&password=secret" 127.0.0.1:8080/login
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.uWoJkSXTLA_RvfLKe12pb4CyxQNxe5_Ovw-N5wfQwkzXz2enbhA9JZf8MmTp9n-TTDcWdY3Fd1SA72_M20G9lQ

The same configuration could be written with environment variables this way:

$ docker run -d -p 8080:8080 -E COOKIE_SECURE=false -e LOGINSRV_JWT_SECRET=my_secret -e LOGINSRV_BACKEND=provider=simple,bob=secret tarent/loginsrv

API

GET /login

Per default, it returns a simple bootstrap styled login form for unauthenticated requests and a page with user info for authenticated requests. When the call accepts a JSON output, the json content of the token is returned to authenticated requests.

The returned HTML follows the UI composition conventions from (lib-compose)[https://github.com/tarent/lib-compose], so it can be embedded into an existing layout.

Parameter-Type Parameter Description
Http-Header Accept: text/html Return the login form or user html. default
Http-Header Accept: application/json Return the user Object as json, or 403 if not authenticated.

GET /login/

Starts the OAuth Web Flow with the configured provider. E.g. GET /login/github redirects to the GitHub login form.

POST /login

Performs the login and returns the JWT. Depending on the content-type and parameters, a classical JSON-Rest or a redirect can be performed.

Runtime Parameters

Parameter-Type Parameter Description
Http-Header Accept: text/html Set the JWT as a cookie named 'jwt_token' default
Http-Header Accept: application/jwt Returns the JWT within the body. No cookie is set
Http-Header Content-Type: application/x-www-form-urlencoded Expect the credentials as form encoded parameters default
Http-Header Content-Type: application/json Take the credentials from the provided JSON object
Post-Parameter username The username
Post-Parameter password The password
Get or Post backTo Dynamic redirect target after login (see (Redirects)[#redirects]) -success-url

Possible Return Codes

Code Meaning Description
200 OK Successfully authenticated
403 Forbidden The credentials are wrong
400 Bad Request Missing parameters
500 Internal Server Error Internal error, e.g. the login provider is not available or failed
303 See Other Sets the JWT as a cookie, if the login succeeds and redirect to the URLs provided in redirectSuccess or redirectError

Hint: The status 401 Unauthorized is not used as a return code to not conflict with an HTTP Basic authentication.

JWT-Refresh

If the POST-Parameters for username and password are missing and a valid JWT-Cookie is part of the request, then the JWT-Cookie is refreshed. This only happens if the jwt-refreshes config option is set to a value greater than 0.

DELETE /login

Deletes the JWT cookie.

For simple usage in web applications, this can also be called by GET|POST /login?logout=true

API Examples

Example:

Default is to return the token as Content-Type application/jwt within the body.

curl -i --data "username=bob&password=secret" http://127.0.0.1:6789/login
HTTP/1.1 200 OK
Content-Type: application/jwt
Date: Mon, 14 Nov 2016 21:35:42 GMT
Content-Length: 100

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.-51G5JQmpJleARHp8rIljBczPFanWT93d_N_7LQGUXU

Example: Credentials as JSON

The credentials can also be sent JSON encoded.

curl -i -H 'Content-Type: application/json'  --data '{"username": "bob", "password": "secret"}' http://127.0.0.1:6789/login
HTTP/1.1 200 OK
Content-Type: application/jwt
Date: Mon, 14 Nov 2016 21:35:42 GMT
Content-Length: 100

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.-51G5JQmpJleARHp8rIljBczPFanWT93d_N_7LQGUXU

Example: web based flow with 'Accept: text/html'

Sets the JWT as a cookie and redirects to a web page.

curl -i -H 'Accept: text/html' --data "username=bob&password=secret" http://127.0.0.1:6789/login
HTTP/1.1 303 See Other
Location: /
Set-Cookie: jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.-51G5JQmpJleARHp8rIljBczPFanWT93d_N_7LQGUXU; HttpOnly

Example: AJAX call with JQuery to fetch a JWT token and create a cookie from it

Creates a cookie from a successful API call to login.

$.ajax({
	url: "http://localhost:8080/login",
	type: 'POST',
	dataType: 'text',
	contentType: 'application/json',
	data: JSON.stringify( { 
		'username': 'demo', 
		'password': 'demo'
	}),
	success: function(data) {
		document.cookie = "jwt_token=" + data + ";path=/";
	},
	error: function (xhr, ajaxOptions, thrownError) {
	}
});

Make sure your main page has JQuery:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

Redirects

The API has support for a redirect query parameter, e.g. ?backTo=/dynamic/return/path. For security reasons, the default behaviour is very restrictive:

  • Only local redirects (same host) are allowed.
  • The Referer header is checked to ensure that the call to the login page came from the same page.

These restrictions are there, to prevent you from unchecked redirect attacks, e.g. phishing or login attacks. If you know, what you are doing, you can disable the Referer check with --redirect-check-referer=false and provide a whitelist file for allowed external domains with --redirect-host-file=/some/domains.txt.

The JWT Token

Depending on the provider, the token may look as follows:

{
  "sub": "smancke",
  "picture": "https://avatars2.githubusercontent.com/u/4291379?v=3",
  "name": "Sebastian Mancke",
  "email": "[email protected]",
  "origin": "github"
}

Provider Backends

Htpasswd

Authentication against htpasswd file. MD5, SHA1 and Bcrypt are supported. But we recommend to only use Bcrypt for security reasons (e.g. htpasswd -B -C 15).

Parameters for the provider:

Parameter-Name Description
file Path to the password file (multiple files can be used by separating them with ';')

Example:

loginsrv -htpasswd file=users

Httpupstream

Authentication against an upstream HTTP server by performing a HTTP Basic authentication request and checking the response for a HTTP 200 OK status code. Anything other than a 200 OK status code will result in a failure to authenticate.

Parameters for the provider:

Parameter-Name Description
upstream HTTP/HTTPS URL to call
skipverify True to ignore TLS errors (optional, false by default)
timeout Request timeout (optional 1m by default, go duration syntax is supported)

Example:

loginsrv -httpupstream upstream=https://google.com,timeout=1s

OSIAM

OSIAM is a secure identity management solution providing REST based services for authentication and authorization. It implements the multiple OAuth2 flows, as well as SCIM for managing the user data.

To start loginsrv against the default OSIAM configuration on the same machine, use the following example.

loginsrv --jwt-secret=jwtsecret --text-logging -osiam endpoint=http://localhost:8080,client_id=example-client,client_secret=secret'

Then go to http://127.0.0.1:6789/login and login with admin/koala.

Simple

Simple is a demo provider for testing only. It holds a user/password table in memory.

Example

loginsrv -simple bob=secret

OAuth2

The OAuth Web Flow (aka 3-legged-OAuth flow) is also supported. Currently the following OAuth provider is supported:

  • GitHub
  • Google
  • Bitbucket
  • Facebook
  • Gitlab

An OAuth provider supports the following parameters:

Parameter-Name Description
client_id OAuth Client ID
client_secret OAuth Client Secret
scope Space separated scope List (optional)
redirect_uri Alternative Redirect URI (optional)

When configuring the OAuth parameters at your external OAuth provider, a redirect URI has to be supplied. This redirect URI has to point to the path /login/<provider>. If not supplied, the OAuth redirect URI is calculated out of the current URL. This should work in most cases and should even work if loginsrv is routed through a reverse proxy, if the headers X-Forwarded-Host and X-Forwarded-Proto are set correctly.

GitHub Startup Example

$ docker run -p 80:80 tarent/loginsrv -github client_id=xxx,client_secret=yyy

Templating

A custom template can be supplied by the parameter template. You can find the original template in login/login_form.go.

The templating uses the Golang template package. A short intro can be found here.

When you specify a custom template, only the layout of the original template is replaced. The partials of the original are still loaded into the template context and can be used by your template. So a minimal unstyled login template could look like this:

<!DOCTYPE html>
<html>
  <head>
      <!-- your styles -->
  <head>
  <body>
      <!-- your header -->

      {{ if .Error}}
        <div class="alert alert-danger" role="alert">
          <strong>Internal Error. </strong> Please try again later.
        </div>
      {{end}}

      {{if .Authenticated}}

         {{template "userInfo" . }}

      {{else}}

        {{template "login" . }}

      {{end}}

      <!-- your footer -->
  </body>
</html>

Custom claims

To customize the content of the JWT token either a file wich contains user data or an endpoint providing claims can be provided.

User file

A user file is a YAML file which contains additional information which is encoded in the token. After successful authentication against a backend system, the user is searched within the file and the content of the claims parameter is used to enhance the user JWT claim parameters.

To match an entry, the user file is searched in linear order and all attributes has to match the data of the authentication backend. The first matching entry will be used and all parameters below the claim attribute are written into the token. The following attributes can be used for matching:

  • sub - the username (all backends)
  • origin - the provider or backend name (all backends)
  • email - the mail address (the OAuth provider)
  • domain - the domain (Google only)
  • groups - the full path string of user groups enclosed in an array (Gitlab only)

Example:

  • The user bob will become the "role": "superAdmin", when authenticating with htpasswd file
  • The user [email protected] will become "role": "admin" and "projects": ["example"], when authenticating with Google OAuth
  • All other Google users with the domain example will become "role": "user" and "projects": ["example"]
  • All other Gitlab users with group example/subgroup and othergroup will become "role": "admin".
  • All others will become "role": "unknown", independent of the authentication provider
- sub: bob
  origin: htpasswd
  claims:
    role: superAdmin

- email: [email protected]
  origin: Google
  claims:
    role: admin
    projects:
      - example

- domain: example.org
  origin: Google
  claims:
    role: user
    projects:
      - example

- groups:
    - example/subgroup
    - othergroup
  origin: gitlab
  claims:
    role: admin

- claims:
    role: unknown

User endpoint

A user endpoint is a http endpoint which provides additional information on an authenticated user. After successful authentication against a backend system, the endpoint gets called and the provided information is used to enhance the user JWT claim parameters.

loginsrv passes these parameters to the endpoint:

  • sub - the username (all backends)
  • origin - the provider or backend name (all backends)
  • email - the mail address (the OAuth provider)
  • domain - the domain (Google only)
  • groups - the full path string of user groups enclosed in an array (Gitlab only)

An interaction looks like this

GET /claims?origin=google&[email protected]&[email protected] HTTP/1.1
Host: localhost:8080
Accept: */*
Authorization: Bearer token

HTTP/1.1 200 OK
Content-Type: application/json

{
  "sub":"[email protected]",
  "uid":"113",
  "origin":"google",
  "permissions": ["read", "write"]
}

loginsrv's People

Contributors

0xflotus avatar afdecastro879 avatar asdptkt avatar b00lduck avatar betrisey avatar chriswessels avatar didasy avatar dobegor avatar domano avatar ducdigital avatar foobar2016 avatar fvosberg avatar g-w avatar huguesalary avatar irony avatar j-rocke avatar jackodsteel avatar kernle32dll avatar lukehandle avatar magikstm avatar motia avatar perenecabuto avatar saltyblu avatar schnatterer avatar schultemarkus avatar shamrin avatar smancke avatar tkrille avatar wahyd4 avatar ymmtmdk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loginsrv's Issues

Small security issue - Caddy jwt-secret value - If default is not used the first jwt-secret is used

---This issue could be a breaking change depending on the caddyfile and exact setup---

My use-case is to have two subdomains providing different content and use two different secret keys.

I tested this minimal caddyfile on Windows 7 x64:

http://sub1.localhost:2015 {
	root "C:\sites\1"

	jwt {
		path /members
		redirect /login
		secret "C:\sites\key1.txt"
	}

	login {
        	success_url /members/phpinfo.php
        	htpasswd file=users1.txt
		jwt-secret aaaaaaa
		cookie-domain sub1.localhost
	}
}

http://sub2.localhost:2015 {
	root "C:\sites\2"

	jwt {
		path /members
		redirect /login
		secret "C:\sites\key2.txt"
	}

	login {
        success_url /members/phpinfo.php
        htpasswd file=users2.txt
	jwt-secret bbbbbbb
	cookie-domain sub2.localhost
    }
}

I checked the produced token there: https://jwt.io/

I noticed the first jwt-secret ('aaaaaaa') is used for both subdomains.

I'm investigating this issue and I'll have a PR in the next few hours.

redirect backTo not working correctly

I'm trying to configure a dynamic redirect on successful login. My Caddyfile looks like

my.domain.com {
    root /var/www
    header / Cache-Control "no-cache"

    fastcgi / /var/run/php-fpm/php-fpm.sock php

    jwt {
      path /
      except /favicon.ico
      redirect /login?backTo={rewrite_uri}
    }

    login {
      htpasswd file=/var/lib/caddy/passwd
    }
}

From what I can gather the referrer host must match the current request host by default.
Here what my request headers look like:
image
You can see that the host and the referrer host are the same. However, the redirect is not working and in the log I am seeing:

"2018-12-10T23:20:29Z" level=warning msg="redirect from referer domain: '', not matching current domain 'ec2.parkerspot.com'" type=application

This seems like a bug. Am I missing something?

README file simple mistake

Hi

There is a simple mistake in the main readme file, section startup examples
there is a parameter -secure-cookie but the real parameter is -cookie-secure.

Facebook provider

Are you interested in having support for Facebook login? (Twitter is also useful in my case).

Oauth2 is supported, so I imagine it could fit in ok. Maybe I'm missing something in the docs?

oauth2: got http status 403 on google get user info

Caddyfile:

localhost:3000 {
  proxy / localhost:3040
  jwt {
    path /
    allow domain readdle.com
  }
  login {
    google "client_id=***,client_secret=***,scope=https://www.googleapis.com/auth/userinfo.profile"
  }
}

Upon login it shows "Internal error" and an error in log: oauth2: got http status 403 on google get user info

Also tried these scopes: https://www.googleapis.com/auth/plus.me, https://www.googleapis.com/auth/plus.login with same effect.

Client ID and Client Secret are created for a fresh sample project. Same Client ID and secret work for bitly/oauth2_proxy, but I'd prefer to use caddy+loginsrv in our setup.

Oauth2

I have the following config:

login {
         google client_id=XXXXX.apps.googleusercontent.com,client_secretXXXXXX,scope=https://www.googleapis.com/auth/userinfo.email
}

How can specify which user to have access?

Argon2 (Argon2i, Argon2d and Argon2id) hashing - Should it be implemented?

Argon2 is available in Golang, PHP and a few other languages.

It is considered safer than Bcrypt, but it is quite less mature.

I don't think it is a required feature, but may be nice to add eventually in the future.

I would categorize it has a possible enhancement at the moment.

Ref:
https://en.wikipedia.org/wiki/Argon2
https://godoc.org/golang.org/x/crypto/argon2
https://crypto.stackexchange.com/questions/30785/password-hashing-security-of-argon2-versus-bcrypt-pbkdf2

Multiple forward slashes in paths may pass-through security with htpasswd

related to caddyserver/caddy#1859.

With this minimal caddyfile:

http://localhost:8080 {

  log stdout  
  root C:\webroot
  ext .html
  header /members Cache-Control "no-cache, no-store, must-revalidate"
  
  jwt {
    path /members
    redirect /login
  }

  login {
        success_url /members/private
        htpasswd file=passwords
  }
}

multiple forward slashes may pass-through the security.

I did these tests:

  1. http://localhost:8080/members/1.jpg (redirects to login)
  2. http://localhost:8080//members/1.jpg (passes through login and shows the image)
  3. http://localhost:8080//members//1.jpg (passes through login and shows the image)
  4. http://localhost:8080/members//1.jpg (redirects to login)

It's a critical vulnerability.

Edge-case that I don't think work as expected - cookie-name

I'm unsure if these should be corrected and how they should be.

At the moment, if you do this:

  1. Different cookie-name in http.login and http.jwt (with this PR BTBurke/caddy-jwt#39)

If you use redirect in http.jwt you are:

  1. Redirected to http.jwt's redirect page that is in your caddyfile
  2. Unable to navigate to any page that is protected by http.login
  3. But, you appear to be authenticated

If you don't use redirect in http.jwt you are:

  1. Displayed a 401 error for the page you navigate to
  2. But, you appear to be authenticated if you navigate to /login

I think best way to correct the issue could be:

  1. Detect such issues when Caddy loads and display a misconfiguration error with details
  2. Make authentication fail (possibly with an internal server error)

I would opt for option 1. @smancke please review how these cases should be handled.

After Login Success API Calls using access token from Oauth2 providers

I've been struggling a little bit finding a way to use the access token for after-login-success API calls to Github and Bitbucket providers. Is there a way I can use the access token, send it somewhere in my code to be saved?

I've seen #8 seems to be the solution to this problem using a post login call back. Will this issue be solved on the short term? Does someone know a way I can actually do a workaround in the meantime? I'm also open to eventually do a contribution but I don't know where or how to start. Any ideas?

Thanks a lot

Correct 'scope' for Google OAuth2

I'm trying to get the Google OAuth2 backend working with Caddy, but I believe I am stuck on finding the right value for the scope parameter. These are what I've tried:

  • profile
  • https://www.googleapis.com/auth/plus.login
  • https://www.googleapis.com/auth/plus.me

but they all error with:

error="invalid google response: no email address returned."

Any thoughts on the scope I should be using?

Just to provide some feedback, I had other issues I ran into along the way, like not having the Google+ API enabled in my Google account, but I had to custom compile Caddy to get this error out of loginsrv by reading the response body and adding print statements here: https://github.com/tarent/loginsrv/blob/master/oauth2/google.go#L46

Thanks for the plugin. This seems to be exactly what I've been waiting for.

Custom Backened

Hi

Can i add my own custom backend for example a database of username and password, to be authenticated against?

Caddy usage - htpasswd file isn't reloaded (on insert, on update or on delete)

Tested on Windows 7 x64:

Launched with: go run main.go

My caddyfile is:

http://localhost:8080 {

log stdout
root C:[path to demo]\demo\webroot
ext .html
header /members Cache-Control "no-cache, no-store, must-revalidate"

jwt {
path /members
redirect /login
}

login {
success_url /members/private
htpasswd file=passwords
}

}

If I:

  1. Add a user
  2. Remove a user
  3. Update a user's password

htpasswd file isn't reloaded.

Another service on my server "adds", "removes" or "updates" users on the htpasswd file I wish to use and I would want loginsrv to use the current credentials available in the file instead of the content it had on launch.

Restrict access by OAuth2 domain

My goal is to be able to limit access to some backend applications using Google OAuth2. I'm a Google Apps user and would like to start by limiting access by domain. Using loginsrv with caddy-jwt there doesn't seem to be a way to limit access based on the email address domain. It seems it would require support for regex in the caddy-jwt plugin for field values or perhaps I'm missing a simpler solution.

I'm wondering if parsing out the domain and including it in the JWT is something that would be in-scope for this plugin. Or if you would be willing to optionally support pulling information from any of the additional scopes that could also be helpful in limiting access, such as user groups: https://developers.google.com/admin-sdk/directory/v1/guides/authorizing

I'd like to tackle this in the most reusable way in case I can contribute some code.

Thanks!

Enhancements on secret handling

Some ideas:

  • The generated secret could be stored in a file, to be preserved through reboots.
  • Support for asymmetric encryption would be good. In that case, the public key could be provided via rest resource.
  • For key rotation in production, a list of keys should be supported in caddy-jwt and loginsrv
  • Auto key rotation would be cool

Github organization and team support

It would be nice with support for allowing whole organizations/teams to login. All teams/orgs can be added to the JWT_TOKEN, and use the jwt plugin to allow users by org/team-name(s). It would be up to the user to add read:org scope, allowing the plugin to also see hidden memberships.

It would be nice with some input about if and how to implement it. Guess I can implement it if you like the idea.

This may also be usable for other backends (ie. google org. for )

PS: Thanks for this awesome project! 😄

Dynamic success URL

I think it would be great if the success URL could be set on a case-by-case basis, as a parameter. Useful when the user has been redirected to the authentication flow automatically—they can then be dropped back on the original URL they were trying to visit, after successfully authenticating.

For username/password-based authentication, I imagine it as a GET parameter on the /login endpoint: /login?return=%2Fmyaccount. A hidden input field with the same value could be added to the form, sending it on as a POST parameter when the authentication is performed. I imagine something similar could be done for the third party service-based authentication methods, for example passing the value of the return parameter as the redirect_uri for GitHub OAUTH.
The existing success-url config entry could be used as a fallback if no return parameter is set.

Need more explanation on `domain` for userfile.yml

Hello guys,

What exactly is the domain that written in the example of your user file?

Is it the hostname that the user is signing on, or is it the domain of the user's email return back from oAuth?

Beside is there any way to validate user's email domain? something like validate the company.info part of [email protected]?

Thank you

Caddy - Use {user} placeholder for logs

Request based on these:
caddyserver/caddy#1542
caddyserver/caddy#1543

It's still under development, but it'll probably be possible with lines similar to these:

// Capture username into {user} placeholder for caddyfile log directive
	// ex:  log / stdout "{remote} - {user} [{when}] {method} {uri} {proto} {status} {size}"
	*r = *r.WithContext(context.WithValue(r.Context(),
httpserver.RemoteUserCtxKey, username))

Set "secure" attribute on JWT token

loginsrv provides the option to set the "httpOnly" cookie attribute for the JWT token, but there seems to be no way to set the "secure" cookie attribute. This is a vulnerability that makes it possible for a network-based attacker (e.g., a compromised WiFi router) to steal the cookie and intrude on the user's authenticated session.

Since the cookie doesn't have the "secure" attribute, browsers will send it in response to plain HTTP requests even if the cookie was set over an HTTPS connection. This is exploitable even if the website isn't configured to be served over HTTP at all. For instance, a network-based attacker could intercept a connection from the browser to any HTTP site and inject a redirect for an HTTP request to the domain running loginsrv. As a result, the browser will transmit the JWT token in the clear, where it can be intercepted by the attacker.

redirect directive "backTo" does not work on OAuth Logout

Hey,

thanks for this awesome piece of software!

I'm using loginsrv as a plugin in Caddy in order to protect some URLs. Users must authenticate with OAuth2 for accessing the restricted pages.

The login redirect works perfectly. If I call https://auth.mysite.com/login/google?backTo=https://mysite.com it will return me automatically after the OAuth Login to https://mysite.com.

Unfortunately, the logout seems to ignore the redirection directive backTo. If I call https://auth.mysite.com/login?logout=true&backTo=https://mysite.com I get correctly logged out, but the displayed page is the standard login page (which by default has just the google button).

Have I missed something?

Thanks,
Tobias

htpasswd - Possible multiple htpasswd file is not documented and another undocumented feature

Main page currently lists this parameter for htpasswd:

file | Path to the password file

This commit added the possibility to use multiple htpasswd files: 6e6acbb

It should probably be documented in the main page.

The possible use of "files" (which may provide the same feature) is currently undocumented:
https://github.com/tarent/loginsrv/blob/master/htpasswd/backend.go#L26

I would suggest picking one or the other and removing the code for the other. I would personally opt to keep only "file" as otherwise it may be a breaking change for some.

gitlab provider?

@smancke - Awesome Library.

Would you be open to an MR enabling the use of Gitlab as an oauth2 provider?

If so, is there a way you recommend I get the domain name of the Gitlab instance to Provider?

I'm not seeing any clean ways to do this.

Submit to Caddy website

Hey @smancke do you have plans to publish this to the Caddy website? Since your directive was added to Caddy and released, it's ready to be used by everyone.

Allow user to supply own login form template

It would be nice if the user could supply their own login form template. I'd recommend

login / {
   loginTemplate mylogin.html
}

They could do a simple static button if need be, or something more complicated using a go template. Should look it up relative to the site's root probably. In any case, should probably cache the template, rather than parsing it each time.

Caddy - Unexpected behavior on path having the right -login-path prefix, but other characters following it

When using Caddy, if you use default -login-path being /login I created a table with current behavior and what I believe are expected behavior:

Test no Path Current behavior Expected behavior
1 /login Displays login page Displays login page
2 /LOGIN Displays login page (if CASE_SENSITIVE_PATH stays "false" which is default) otherwise returns a 404 Displays login page (if CASE_SENSITIVE_PATH stays "false" which is default) otherwise displays a login page
3 /loginz Displays login page 404
4 /login/ Displays login page 404
5 /login/z Displays login page 404
6 /loginz/z Displays login page 404

(*) I'm not 100% sure on behavior for test 2 as I tested on Windows 7 x64 and this OS isn't case sensitive. It would need to be confirmed on another OS.

I think this should be adjusted for Caddy and probably for loginsrv by itself as well.

I think these lines could be adjusted :
Caddy https://github.com/tarent/loginsrv/blob/7a8566d795ccd0337dbd35078817f06ae5edccb1/caddy/handler.go#L42
loginsrv by itself https://github.com/tarent/loginsrv/blob/7a8566d795ccd0337dbd35078817f06ae5edccb1/login/handler.go#L78

@smancke I'll submit a PR for Caddy you can review.

This change would be a change of behavior and should be mentioned in next version if it is modified.

Bitbucket Oauth2 support

I've working with this library for a couple of months, but now we need Bitbucket Oauth2 support. Would be nice to add it to the providers list.

I can actually start working on this.

oauth callback parameters not handled for errors

While setting up a new site, as expected there was a mismatch in the redirect URI (next step was to fix that, testing the first step). What surprised me is that nothing was shown in the login page generated by loginsrv, using the caddy plugin, when I was redirected back to the base site.

The callback URL parameters included:

  • error=redirect_uri_mismatch
  • error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.
  • error_uri=....
  • state=....

It would be good if this scenarios could be handled cleanly.

PHP $_SERVER['REMOTE_USER'] not set

I've been able to get Caddy with http.login and http.jwt working with htpasswd. I'm presented with a login page and after I authenticate I can see the resources.

I'm using fastcgi with php-fpm to server php files. The app I'm running relies on $_SERVER['REMOTE_USER'] to get the logged in user, but this variable is not set after I login and try to print it from php.

Is there anything I can do to make sure this variable is populated with the name I authenticated with?

Brute force protection on htpasswd login backend

I've been getting some brute force attempts recently on the htpasswd login protection used with caddy and loginsrv. I've been looking for a way to mitigate these.

I did get such attacks from time to time with apache. I use fail2ban for these on apache.

Would there be a free solution that may be added that may fit within the scope of the project that may be used on a static site solely with html, css and javascript?

I was thinking about Google Recaptcha on the login page as it seems relatively well-known:
https://www.google.com/recaptcha/intro/

Or is there a solution available at the moment?

It wouldn't have to be 100% bullet-proof, but I'm looking for something that would help mitigate these.

OpenIdConnect/Keycloak Support

Would be greate to implement openidconnect in addition of the proprietary outh2 flows of github and google. Also this would then integrate with keycloak and enable a broad amount of integration scenarios. Like serving LDAP/SAML via keycloak instead of implementing everything here again.

Missing viewport meta tag

When I view the login form on a mobile device it looks super small. This surprised me because I know Bootstrap is responsive and mobile first.

I looked in the template and I see that there is a viewport meta tag in the head https://github.com/tarent/loginsrv/blob/23bd16e1ae8f7c8b8442b0119e7d4a25a7ae9cf9/login/login_form.go#L107

However, when inspecting the login form using developer tools it appears that the viewport meta tag is not present:
image

Any ideas as to why this meta element is not present when rendering the login page?

Make subdirective names consistent

Mostly a nit, but directives (and subdirectives) usually follow underscore_convention rather than camelCase or hyphen-convention.

(I realize this isn't clear up front; I'm finishing drafting up a new wiki page in the Caddy plugin developer docs to describe these little things that plugin developers should know.)

Is loginsrv 1.2.4 available in Caddy 0.10.13?

Hello,

Is loginsrv 1.2.4 available in Caddy 0.10.13? I need to use new dynamic redirects and user claims files, but when using those features, Caddy 0.10.13 says it can't process my config:

Here is my config:

login { login_path /login google client_id={$GOOGLE_CLIENT_ID},client_secret={$GOOGLE_CLIENT_SECRET},scope=openid%20email redirect true redirect_query_parameter redirect_uri redirect_check_referer false cookie_http_only true cookie_name jwt_token cookie_domain XXXX user_file /etc/caddy/users.yml }

Thank you :-)

Post login callbacks

It would be great to support a configurable callback after a successful login:

  • As go function, which could be registered
  • As http endpoint

The callback should be receive the following data:

  • claim data
  • the raw user data from the oauth provider
  • The access token from the oauth provider

A callback should be able to return a modified claim data object.

Support $2a$ bcrypt prefix

golang.org/x/crypto/bcrypt, generate $2a$ bcrypt prefix, it would be logical to authenticate against this prefix as well !?

Caddyfile path parameter is a bit confusing

I had to do some digging to see why I need to supply login / { at all. I first thought that was the "protected" paths, but since this does no authorization at all, that wasn't it.

Turns out that is the location to mount the "/login" routes. Does that really need to be a required top level argument? What if it was a simple config line login_path that defaults to /login or something like that?

Dockerfile without USER

Currently the container runs as root. It would be better to create a user specifically for running loginsrv in the Dockerfile.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.