// Copyright 2019 Drone IO, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package session import ( "encoding/json" "errors" "io/ioutil" "net/http" "github.com/drone/drone/core" "github.com/dgrijalva/jwt-go" ) type legacy struct { *session mapping map[string]string } // Legacy returns a session manager that is capable of mapping // legacy tokens to 1.0 users using a mapping file. func Legacy(users core.UserStore, config Config) (core.Session, error) { base := &session{ secret: []byte(config.Secret), secure: config.Secure, timeout: config.Timeout, users: users, } out, err := ioutil.ReadFile(config.MappingFile) if err != nil { return nil, err } mapping := map[string]string{} err = json.Unmarshal(out, &mapping) if err != nil { return nil, err } return &legacy{base, mapping}, nil } func (s *legacy) Get(r *http.Request) (*core.User, error) { switch { case isAuthorizationToken(r): return s.fromToken(r) case isAuthorizationParameter(r): return s.fromToken(r) default: return s.fromSession(r) } } func (s *legacy) fromToken(r *http.Request) (*core.User, error) { extracted := extractToken(r) // determine if the token is a legacy token based on length. // legacy tokens are > 64 characters. if len(extracted) < 64 { return s.users.FindToken(r.Context(), extracted) } token, err := jwt.Parse(extracted, func(token *jwt.Token) (interface{}, error) { // validate the signing method _, ok := token.Method.(*jwt.SigningMethodHMAC) if !ok { return nil, errors.New("Legacy token: invalid signature") } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, errors.New("Legacy token: invalid claim format") } // extract the username claim claim, ok := claims["text"] if !ok { return nil, errors.New("Legacy token: invalid format") } // lookup the username to get the secret secret, ok := s.mapping[claim.(string)] if !ok { return nil, errors.New("Legacy token: cannot lookup user") } return []byte(secret), nil }) if err != nil { return nil, err } return s.users.FindLogin( r.Context(), token.Claims.(jwt.MapClaims)["text"].(string), ) }