11// Copyright 2018 Drone.IO Inc.
2- // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
2+ // Copyright 2022 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
33//
44// Licensed under the Apache License, Version 2.0 (the "License");
55// you may not use this file except in compliance with the License.
@@ -43,19 +43,24 @@ const (
4343)
4444
4545type Gitea struct {
46- URL string
47- Machine string
48- ClientID string
49- ClientSecret string
50- SkipVerify bool
46+ URL string
47+ Machine string
48+ ClientID string
49+ ClientSecret string
50+ SkipVerify bool
51+ RevProxyAuth bool
52+ RevProxyAuthHeader string
53+ RevProxyAuthHeaderValue string
5154}
5255
5356// Opts defines configuration options.
5457type Opts struct {
55- URL string // Gitea server url.
56- Client string // OAuth2 Client ID
57- Secret string // OAuth2 Client Secret
58- SkipVerify bool // Skip ssl verification.
58+ URL string // Gitea server url.
59+ Client string // OAuth2 Client ID
60+ Secret string // OAuth2 Client Secret
61+ SkipVerify bool // Skip ssl verification.
62+ RevProxyAuth bool // Enable reverse proxy authentication using RevProxyAuthHeader.
63+ RevProxyAuthHeader string // Name of HTTP header with username for reverse proxy authentication.
5964}
6065
6166// New returns a Remote implementation that integrates with Gitea,
@@ -70,17 +75,64 @@ func New(opts Opts) (remote.Remote, error) {
7075 u .Host = host
7176 }
7277 return & Gitea {
73- URL : opts .URL ,
74- Machine : u .Host ,
75- ClientID : opts .Client ,
76- ClientSecret : opts .Secret ,
77- SkipVerify : opts .SkipVerify ,
78+ URL : opts .URL ,
79+ Machine : u .Host ,
80+ ClientID : opts .Client ,
81+ ClientSecret : opts .Secret ,
82+ SkipVerify : opts .SkipVerify ,
83+ RevProxyAuth : opts .RevProxyAuth ,
84+ RevProxyAuthHeader : opts .RevProxyAuthHeader ,
7885 }, nil
7986}
8087
81- // Login authenticates an account with Gitea using basic authentication. The
82- // Gitea account details are returned when the user is successfully authenticated.
88+ // Login authenticates an account with Gitea. The Gitea account details
89+ // are returned when the user is successfully authenticated.
8390func (c * Gitea ) Login (ctx context.Context , w http.ResponseWriter , req * http.Request ) (* model.User , error ) {
91+ // Authenticate using reverse proxy header if enabled.
92+ if c .RevProxyAuth {
93+ c .ClientID = req .Header .Get (c .RevProxyAuthHeader )
94+ c .RevProxyAuthHeaderValue = c .ClientID
95+ c .ClientSecret = ""
96+
97+ client , err := c .newClientBasicAuth (ctx , c .ClientID , "" )
98+ if err != nil {
99+ return nil , err
100+ }
101+
102+ // Since api does not return token secret, if drone token exists create new one.
103+ resp , err := client .DeleteAccessToken ("drone" )
104+ if err != nil && ! (resp != nil && resp .StatusCode == 404 ) {
105+ return nil , err
106+ }
107+ token , _ , terr := client .CreateAccessToken (
108+ gitea.CreateAccessTokenOption {Name : "drone" },
109+ )
110+ if terr != nil {
111+ return nil , terr
112+ }
113+ accessToken := token .Token
114+
115+ client , err = c .newClientToken (ctx , accessToken )
116+ if err != nil {
117+ return nil , err
118+ }
119+
120+ account , _ , err := client .GetMyUserInfo ()
121+ if err != nil {
122+ return nil , err
123+ }
124+
125+ return & model.User {
126+ Token : accessToken ,
127+ Secret : "" ,
128+ Expiry : 0 ,
129+ Login : account .UserName ,
130+ Email : account .Email ,
131+ Avatar : expandAvatar (c .URL , account .AvatarURL ),
132+ }, nil
133+ }
134+
135+ // oAuth2 authentication.
84136 config := & oauth2.Config {
85137 ClientID : c .ClientID ,
86138 ClientSecret : c .ClientSecret ,
@@ -443,6 +495,22 @@ func (c *Gitea) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.
443495 return parseHook (r )
444496}
445497
498+ // authTransport forwards authentication HTTP header to gitea.
499+ type authTransport struct {
500+ headerName string
501+ headerValue string
502+ underlyingTransport http.RoundTripper
503+ }
504+
505+ func (t * authTransport ) RoundTrip (req * http.Request ) (* http.Response , error ) {
506+ req .Header .Add (t .headerName , t .headerValue )
507+ if t .underlyingTransport != nil {
508+ return t .underlyingTransport .RoundTrip (req )
509+ } else {
510+ return http .DefaultTransport .RoundTrip (req )
511+ }
512+ }
513+
446514// helper function to return the Gitea client with Token
447515func (c * Gitea ) newClientToken (ctx context.Context , token string ) (* gitea.Client , error ) {
448516 httpClient := & http.Client {}
@@ -451,9 +519,38 @@ func (c *Gitea) newClientToken(ctx context.Context, token string) (*gitea.Client
451519 TLSClientConfig : & tls.Config {InsecureSkipVerify : true },
452520 }
453521 }
522+ // Forward authentication header in every HTTP request to Gitea
523+ // in reverse proxy authentication mode.
524+ if c .RevProxyAuth {
525+ httpClient .Transport = & authTransport {
526+ headerName : c .RevProxyAuthHeader ,
527+ headerValue : c .RevProxyAuthHeaderValue ,
528+ underlyingTransport : httpClient .Transport ,
529+ }
530+ }
454531 return gitea .NewClient (c .URL , gitea .SetToken (token ), gitea .SetHTTPClient (httpClient ), gitea .SetContext (ctx ))
455532}
456533
534+ // helper function to return the Gitea client with Basic Auth
535+ func (c * Gitea ) newClientBasicAuth (ctx context.Context , username , password string ) (* gitea.Client , error ) {
536+ httpClient := & http.Client {}
537+ if c .SkipVerify {
538+ httpClient .Transport = & http.Transport {
539+ TLSClientConfig : & tls.Config {InsecureSkipVerify : true },
540+ }
541+ }
542+ // Forward authentication header in every HTTP request to Gitea
543+ // in reverse proxy authentication mode.
544+ if c .RevProxyAuth {
545+ httpClient .Transport = & authTransport {
546+ headerName : c .RevProxyAuthHeader ,
547+ headerValue : c .RevProxyAuthHeaderValue ,
548+ underlyingTransport : httpClient .Transport ,
549+ }
550+ }
551+ return gitea .NewClient (c .URL , gitea .SetBasicAuth (username , password ), gitea .SetHTTPClient (httpClient ), gitea .SetContext (ctx ))
552+ }
553+
457554// getStatus is a helper function that converts a Woodpecker
458555// status to a Gitea status.
459556func getStatus (status model.StatusValue ) gitea.StatusState {
0 commit comments