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