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