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