2019-01-16 17:01:38 +02:00
package auth
import (
2020-07-08 00:57:52 +03:00
"errors"
2019-02-20 13:53:25 +13:00
"log"
2019-05-24 18:04:58 +12:00
"net/http"
2019-01-18 10:13:33 +02:00
"github.com/asaskevich/govalidator"
2019-01-16 17:01:38 +02:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
2019-03-21 14:20:14 +13:00
"github.com/portainer/portainer/api"
2020-07-08 00:57:52 +03:00
bolterrors "github.com/portainer/portainer/api/bolt/errors"
httperrors "github.com/portainer/portainer/api/http/errors"
2019-01-16 17:01:38 +02:00
)
2019-01-18 10:13:33 +02:00
type oauthPayload struct {
Code string
}
func ( payload * oauthPayload ) Validate ( r * http . Request ) error {
if govalidator . IsNull ( payload . Code ) {
2020-07-08 00:57:52 +03:00
return errors . New ( "Invalid OAuth authorization code" )
2019-01-18 10:13:33 +02:00
}
return nil
}
2020-08-05 11:36:46 +03:00
func ( handler * Handler ) authenticateOAuth ( code string , settings * portainer . OAuthSettings ) ( string , error ) {
if code == "" {
return "" , errors . New ( "Invalid OAuth authorization code" )
2019-02-18 14:46:34 +13:00
}
2020-08-05 11:36:46 +03:00
if settings == nil {
return "" , errors . New ( "Invalid OAuth configuration" )
2019-02-18 14:46:34 +13:00
}
2020-08-05 11:36:46 +03:00
username , err := handler . OAuthService . Authenticate ( code , settings )
2019-02-18 14:46:34 +13:00
if err != nil {
2020-08-05 11:36:46 +03:00
log . Printf ( "[DEBUG] - Unable to authenticate user via OAuth: %v" , err )
return "" , nil
2019-02-18 14:46:34 +13:00
}
2020-08-05 11:36:46 +03:00
return username , nil
2019-02-18 14:46:34 +13:00
}
2019-01-18 10:15:02 +02:00
func ( handler * Handler ) validateOAuth ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
2019-01-16 17:01:38 +02:00
var payload oauthPayload
err := request . DecodeAndValidateJSONPayload ( r , & payload )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid request payload" , err }
}
2020-05-20 17:23:15 +12:00
settings , err := handler . DataStore . Settings ( ) . Settings ( )
2019-01-16 17:01:38 +02:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve settings from the database" , err }
}
if settings . AuthenticationMethod != 3 {
2020-07-08 00:57:52 +03:00
return & httperror . HandlerError { http . StatusForbidden , "OAuth authentication is not enabled" , errors . New ( "OAuth authentication is not enabled" ) }
2019-01-16 17:01:38 +02:00
}
2020-08-05 11:36:46 +03:00
username , err := handler . authenticateOAuth ( payload . Code , & settings . OAuthSettings )
2019-01-16 17:01:38 +02:00
if err != nil {
2019-02-20 13:53:25 +13:00
log . Printf ( "[DEBUG] - OAuth authentication error: %s" , err )
2020-07-08 00:57:52 +03:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to authenticate through OAuth" , httperrors . ErrUnauthorized }
2019-01-16 17:01:38 +02:00
}
2020-05-20 17:23:15 +12:00
user , err := handler . DataStore . User ( ) . UserByUsername ( username )
2020-07-08 00:57:52 +03:00
if err != nil && err != bolterrors . ErrObjectNotFound {
2019-01-16 17:01:38 +02:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve a user with the specified username from the database" , err }
}
2019-01-18 10:56:16 +02:00
if user == nil && ! settings . OAuthSettings . OAuthAutoCreateUsers {
2020-07-08 00:57:52 +03:00
return & httperror . HandlerError { http . StatusForbidden , "Account not created beforehand in Portainer and automatic user provisioning not enabled" , httperrors . ErrUnauthorized }
2019-01-16 17:01:38 +02:00
}
2019-01-18 10:56:16 +02:00
if user == nil {
user = & portainer . User {
2020-08-11 08:41:37 +03:00
Username : username ,
Role : portainer . StandardUserRole ,
2019-01-16 17:01:38 +02:00
}
2020-05-20 17:23:15 +12:00
err = handler . DataStore . User ( ) . CreateUser ( user )
2019-01-16 17:01:38 +02:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist user inside the database" , err }
}
2019-02-17 19:01:42 +13:00
if settings . OAuthSettings . DefaultTeamID != 0 {
membership := & portainer . TeamMembership {
UserID : user . ID ,
TeamID : settings . OAuthSettings . DefaultTeamID ,
Role : portainer . TeamMember ,
}
2020-05-20 17:23:15 +12:00
err = handler . DataStore . TeamMembership ( ) . CreateTeamMembership ( membership )
2019-02-17 19:01:42 +13:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist team membership inside the database" , err }
}
}
2019-12-04 15:32:55 +13:00
2019-01-16 17:01:38 +02:00
}
2019-01-18 10:56:16 +02:00
return handler . writeToken ( w , user )
2019-01-16 17:01:38 +02:00
}