-
-
Save cuchac/36e6c774402aa271fc7c970158ba39d9 to your computer and use it in GitHub Desktop.
GitLab and Rancher 2 Authentication Proxy
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
#!/bin/bash | |
set -ex | |
go build -o rancher_gitlab_proxy main.go | |
CGO_ENABLED=0 GOOS=linux go build -o rancher_gitlab_proxy_linux main.go |
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
FROM golang:1.14 AS builder | |
WORKDIR /go/src/app | |
COPY . . | |
RUN sh build.sh | |
FROM alpine:latest | |
RUN apk --no-cache add ca-certificates | |
WORKDIR /root/ | |
COPY --from=builder /go/src/app/rancher_gitlab_proxy_linux rancher_gitlab_proxy_linux | |
CMD ["./rancher_gitlab_proxy_linux"] | |
EXPOSE 8888 |
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
# in GitLab config - gitlab.rb | |
nginx['custom_gitlab_server_config'] = " | |
# CONNECTION TO rancher-gitlab-proxy BEGIN | |
location /login/oauth/authorize { | |
proxy_pass http://127.0.0.1:8888; | |
} | |
location /login/oauth/access_token { | |
proxy_pass http://127.0.0.1:8888; | |
} | |
location /api/v3/user { | |
proxy_pass http://127.0.0.1:8888; | |
} | |
location /api/v3/teams/ { | |
proxy_pass http://127.0.0.1:8888; | |
} | |
location /api/v3/search/users { | |
proxy_pass http://127.0.0.1:8888; | |
} | |
# CONNECTION TO rancher-gitlab-proxy END | |
" |
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
module sandstorm.de/rancher-gitlab-proxy | |
go 1.15 | |
require ( | |
github.com/julienschmidt/httprouter v1.3.0 | |
github.com/xanzy/go-gitlab v0.40.2 | |
) |
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 ( | |
"encoding/json" | |
"fmt" | |
"github.com/julienschmidt/httprouter" | |
"github.com/xanzy/go-gitlab" | |
"net/http" | |
"strconv" | |
"strings" | |
) | |
// !!! ADJUST | |
const gitlab_url = "https://gitlab.com" | |
const rancher_url = "https://rancher-url.de" | |
// !!! ADJUST | |
///////////////// MAIN | |
func main() { | |
router := httprouter.New() | |
router.GET("/login/oauth/authorize", oauthAuthorize) | |
router.POST("/login/oauth/access_token", oauthAccessToken) | |
router.GET("/api/v3/user", apiV3User) | |
router.GET("/api/v3/user/:id", apiV3UserId) | |
router.GET("/api/v3/teams/:id", apiV3TeamsId) | |
router.GET("/api/v3/search/users", apiV3SearchUsers) | |
fmt.Println("Listening to 127.0.0.1:8888") | |
if err := http.ListenAndServe("127.0.0.1:8888", router); err != nil { | |
panic(err) | |
} | |
} | |
///////////////// API | |
func oauthAuthorize(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
v := req.URL.Query() | |
v.Add("response_type", "code") | |
v.Add("scope", "read_api") | |
target := gitlab_url + "/oauth/authorize?" + v.Encode() | |
http.Redirect(w, req, target, http.StatusTemporaryRedirect) | |
} | |
func oauthAccessToken(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
v := req.URL.Query() | |
v.Add("grant_type", "authorization_code") | |
v.Add("redirect_uri", rancher_url + "/verify-auth") | |
target := gitlab_url + "/oauth/token?" + v.Encode() | |
http.Redirect(w, req, target, http.StatusTemporaryRedirect) | |
} | |
func apiV3User(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
gitlabClient := createGitlabClient(req) | |
gitlabUser, _, err := gitlabClient.Users.CurrentUser() | |
if err != nil { | |
panic(err) | |
} | |
githubAccount := convertGitlabUserToAccount(gitlabUser) | |
jsonStr, _ := json.Marshal(githubAccount) | |
w.Write(jsonStr) | |
} | |
func apiV3UserId(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
// Workaround to deal with routing library | |
if ps.ByName("id") == "orgs" { | |
apiV3UserOrgs(w, req, ps) | |
return | |
} | |
if ps.ByName("id") == "teams" { | |
apiV3UserTeams(w, req, ps) | |
return | |
} | |
gitlabClient := createGitlabClient(req) | |
id, _ := strconv.Atoi(ps.ByName("id")) | |
// user | |
gitlabUser, _, err := gitlabClient.Users.GetUser(id) | |
if err != nil { | |
panic(err) | |
} | |
githubAccount := convertGitlabUserToAccount(gitlabUser) | |
jsonStr, _ := json.Marshal(githubAccount) | |
w.Write(jsonStr) | |
} | |
func apiV3UserOrgs(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
result := make([]string, 0) | |
jsonStr, _ := json.Marshal(result) | |
w.Write(jsonStr) | |
} | |
func apiV3UserTeams(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
gitlabClient := createGitlabClient(req) | |
allAvailable := false | |
result := make([]Team, 0, 0) | |
listGroupsOptions := &gitlab.ListGroupsOptions{ | |
ListOptions: gitlab.ListOptions{ | |
}, | |
// here, we only want to search for groups WHICH WE ARE MEMBER OF!!! | |
AllAvailable: &allAvailable, | |
} | |
for { | |
gitlabGroups, resp, err := gitlabClient.Groups.ListGroups(listGroupsOptions) | |
if err != nil { | |
panic(err) | |
} | |
for _, gitlabGroup := range gitlabGroups { | |
team := convertGitlabGroupToTeam(gitlabGroup) | |
result = append(result, *team) | |
} | |
// Exit the loop when we've seen all pages. | |
if resp.CurrentPage >= resp.TotalPages { | |
break | |
} | |
// Update the page number to get the next page. | |
listGroupsOptions.ListOptions.Page = resp.NextPage | |
} | |
jsonStr, _ := json.Marshal(result) | |
w.Write(jsonStr) | |
} | |
func apiV3TeamsId(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
gitlabClient := createGitlabClient(req) | |
id, _ := strconv.Atoi(ps.ByName("id")) | |
gitlabGroup, _, err := gitlabClient.Groups.GetGroup(id) | |
if err != nil { | |
panic(err) | |
} | |
team := convertGitlabGroupToTeam(gitlabGroup) | |
jsonStr, _ := json.Marshal(team) | |
w.Write(jsonStr) | |
} | |
type searchResult struct { | |
Items []*Account `json:"items"` | |
} | |
func apiV3SearchUsers(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { | |
query := req.URL.Query().Get("q") | |
gitlabClient := createGitlabClient(req) | |
searchResult := &searchResult{ | |
Items: make([]*Account, 0), | |
} | |
shouldSearchUsers := true | |
shouldSearchOrgs := true | |
if strings.Contains(query, "type:org") { | |
shouldSearchUsers = false | |
shouldSearchOrgs = true | |
query = strings.ReplaceAll(query, "type:org", "") | |
} | |
if shouldSearchOrgs { | |
allAvailable := true | |
gitlabGroups, _, err := gitlabClient.Groups.ListGroups(&gitlab.ListGroupsOptions{ | |
Search: &query, | |
// we want to find ALL groups (which are not fully private) | |
AllAvailable: &allAvailable, | |
}) | |
if err != nil { | |
panic(err) | |
} | |
for _, gitlabGroup := range gitlabGroups { | |
githubOrg := convertGitlabGroupToAccount(gitlabGroup) | |
searchResult.Items = append(searchResult.Items, githubOrg) | |
} | |
} | |
if shouldSearchUsers { | |
gitlabUsers, _, err := gitlabClient.Users.ListUsers(&gitlab.ListUsersOptions{ | |
Search: &query, | |
}) | |
if err != nil { | |
panic(err) | |
} | |
for _, gitlabUser := range gitlabUsers { | |
githubAccount := convertGitlabUserToAccount(gitlabUser) | |
searchResult.Items = append(searchResult.Items, githubAccount) | |
} | |
} | |
jsonStr, _ := json.Marshal(searchResult) | |
w.Write(jsonStr) | |
} | |
///////////////// HELPERS | |
// https://docs.github.com/en/free-pro-team@latest/rest/reference/users#get-the-authenticated-user | |
// copied from https://github.com/rancher/rancher/blob/2506427ba7bd31edf12f7110b7fdb8b2defe8eb3/pkg/auth/providers/github/github_account.go#L12 | |
type Account struct { | |
ID int `json:"id,omitempty"` | |
Login string `json:"login,omitempty"` | |
Name string `json:"name,omitempty"` | |
AvatarURL string `json:"avatar_url,omitempty"` | |
HTMLURL string `json:"html_url,omitempty"` | |
// "Type" must be "user", "team", oder "org" | |
Type string `json:"type,omitempty"` | |
} | |
//Team defines properties a team on github has | |
type Team struct { | |
ID int `json:"id,omitempty"` | |
Organization map[string]interface{} `json:"organization,omitempty"` | |
Name string `json:"name,omitempty"` | |
Slug string `json:"slug,omitempty"` | |
} | |
func createGitlabClient(req *http.Request) *gitlab.Client { | |
authorizationHeader := req.Header.Get("Authorization") | |
t := strings.Split(authorizationHeader, " ") | |
token := t[1] | |
gitlabClient, err := gitlab.NewOAuthClient(token, gitlab.WithBaseURL(gitlab_url + "/api/v4")) | |
if err != nil { | |
panic(err) | |
} | |
return gitlabClient | |
} | |
func convertGitlabUserToAccount(gitlabUser *gitlab.User) *Account { | |
return &Account{ | |
ID: gitlabUser.ID, | |
Login: gitlabUser.Username, | |
Name: gitlabUser.Name, | |
AvatarURL: gitlabUser.AvatarURL, | |
HTMLURL: "", | |
Type: "user", | |
} | |
} | |
func convertGitlabGroupToAccount(gitlabGroup *gitlab.Group) *Account { | |
return &Account{ | |
ID: gitlabGroup.ID, | |
Login: gitlabGroup.Path, | |
Name: gitlabGroup.Name, | |
AvatarURL: gitlabGroup.AvatarURL, | |
HTMLURL: "", | |
Type: "team", | |
} | |
} | |
func convertGitlabGroupToTeam(gitlabGroup *gitlab.Group) *Team { | |
org := make(map[string]interface{}) | |
org["login"] = gitlabGroup.Path | |
org["avatar_url"] = gitlabGroup.AvatarURL | |
return &Team{ | |
ID: gitlabGroup.ID, | |
Organization: org, | |
Name: gitlabGroup.Name, | |
Slug: gitlabGroup.Path, | |
} | |
} |
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
[Unit] | |
Description=rancher-gitlab-proxy | |
Wants=network-online.target | |
After=network-online.target | |
[Service] | |
Type=simple | |
User=gitlab-www | |
Group=gitlab-www | |
ExecStart=/usr/local/bin/rancher_gitlab_proxy | |
SyslogIdentifier=rancher-gitlab-proxy | |
Restart=always | |
[Install] | |
WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment