Created
October 31, 2018 23:55
-
-
Save lxfontes/ba933c42fb41515f78ebd56c3d96616f to your computer and use it in GitHub Desktop.
golang ssh server with github authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"github.com/gliderlabs/ssh" | |
"github.com/pkg/errors" | |
gossh "golang.org/x/crypto/ssh" | |
) | |
func fetchKeys(ctx context.Context, username string) ([]ssh.PublicKey, error) { | |
keyURL := fmt.Sprintf("https://github.com/%s.keys", username) | |
log.Println(keyURL) | |
req, err := http.NewRequest("GET", keyURL, nil) | |
if err != nil { | |
return nil, errors.Wrap(err, "creating request") | |
} | |
req = req.WithContext(ctx) | |
client := http.DefaultClient | |
res, err := client.Do(req) | |
if err != nil { | |
return nil, errors.Wrap(err, "fetching keys") | |
} | |
defer res.Body.Close() | |
if res.StatusCode != 200 { | |
return nil, errors.New("invalid response from github") | |
} | |
authorizedKeysBytes, err := ioutil.ReadAll(res.Body) | |
if err != nil { | |
return nil, errors.Wrap(err, "reading body") | |
} | |
keys := []ssh.PublicKey{} | |
for len(authorizedKeysBytes) > 0 { | |
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes) | |
if err != nil { | |
return nil, errors.Wrap(err, "parsing key") | |
} | |
keys = append(keys, pubKey) | |
authorizedKeysBytes = rest | |
} | |
return keys, nil | |
} | |
func main() { | |
ssh.Handle(func(s ssh.Session) { | |
authorizedKey := gossh.MarshalAuthorizedKey(s.PublicKey()) | |
io.WriteString(s, fmt.Sprintf("public key used by %s:\n", s.User())) | |
s.Write(authorizedKey) | |
}) | |
publicKeyOption := ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool { | |
user := ctx.User() | |
keys, err := fetchKeys(ctx, user) | |
if err != nil { | |
log.Printf("%s: %s", user, err) | |
return false | |
} | |
for _, k := range keys { | |
if ssh.KeysEqual(key, k) { | |
log.Println(user, "allowed") | |
return true | |
} | |
} | |
log.Println(user, "denied") | |
return false | |
}) | |
log.Fatal(ssh.ListenAndServe(":2222", nil, publicKeyOption)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment