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