github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/common/password.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/state"
    13  )
    14  
    15  var logger = loggo.GetLogger("juju.apiserver.common")
    16  
    17  // PasswordChanger implements a common SetPasswords method for use by
    18  // various facades.
    19  type PasswordChanger struct {
    20  	st           state.EntityFinder
    21  	getCanChange GetAuthFunc
    22  }
    23  
    24  // NewPasswordChanger returns a new PasswordChanger. The GetAuthFunc will be
    25  // used on each invocation of SetPasswords to determine current permissions.
    26  func NewPasswordChanger(st state.EntityFinder, getCanChange GetAuthFunc) *PasswordChanger {
    27  	return &PasswordChanger{
    28  		st:           st,
    29  		getCanChange: getCanChange,
    30  	}
    31  }
    32  
    33  // SetPasswords sets the given password for each supplied entity, if possible.
    34  func (pc *PasswordChanger) SetPasswords(args params.EntityPasswords) (params.ErrorResults, error) {
    35  	result := params.ErrorResults{
    36  		Results: make([]params.ErrorResult, len(args.Changes)),
    37  	}
    38  	if len(args.Changes) == 0 {
    39  		return result, nil
    40  	}
    41  	canChange, err := pc.getCanChange()
    42  	if err != nil {
    43  		return params.ErrorResults{}, errors.Trace(err)
    44  	}
    45  	for i, param := range args.Changes {
    46  		tag, err := names.ParseTag(param.Tag)
    47  		if err != nil {
    48  			result.Results[i].Error = ServerError(ErrPerm)
    49  			continue
    50  		}
    51  		if !canChange(tag) {
    52  			result.Results[i].Error = ServerError(ErrPerm)
    53  			continue
    54  		}
    55  		if err := pc.setPassword(tag, param.Password); err != nil {
    56  			result.Results[i].Error = ServerError(err)
    57  		}
    58  	}
    59  	return result, nil
    60  }
    61  
    62  func (pc *PasswordChanger) setMongoPassword(entity state.Entity, password string) error {
    63  	type mongoPassworder interface {
    64  		SetMongoPassword(password string) error
    65  	}
    66  	// We set the mongo password first on the grounds that
    67  	// if it fails, the agent in question should still be able
    68  	// to authenticate to another API server and ask it to change
    69  	// its password.
    70  	if entity0, ok := entity.(mongoPassworder); ok {
    71  		if err := entity0.SetMongoPassword(password); err != nil {
    72  			return err
    73  		}
    74  		logger.Infof("setting mongo password for %q", entity.Tag())
    75  		return nil
    76  	}
    77  	// TODO(dfc) fix
    78  	return NotSupportedError(entity.Tag(), "mongo access")
    79  }
    80  
    81  func (pc *PasswordChanger) setPassword(tag names.Tag, password string) error {
    82  	type jobsGetter interface {
    83  		Jobs() []state.MachineJob
    84  	}
    85  	var err error
    86  	entity0, err := pc.st.FindEntity(tag)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	entity, ok := entity0.(state.Authenticator)
    91  	if !ok {
    92  		return NotSupportedError(tag, "authentication")
    93  	}
    94  	if entity, ok := entity0.(jobsGetter); ok {
    95  		for _, job := range entity.Jobs() {
    96  			paramsJob := job.ToParams()
    97  			if paramsJob.NeedsState() {
    98  				err = pc.setMongoPassword(entity0, password)
    99  				break
   100  			}
   101  		}
   102  	}
   103  	if err == nil {
   104  		err = entity.SetPassword(password)
   105  		logger.Infof("setting password for %q", tag)
   106  	}
   107  	return err
   108  }