doLoginIfNeeded check if the user is logged in looking at the ssh agent, if it's not it will do the login flow.
(ctx *cli.Context, subject string)
| 98 | // doLoginIfNeeded check if the user is logged in looking at the ssh agent, if |
| 99 | // it's not it will do the login flow. |
| 100 | func doLoginIfNeeded(ctx *cli.Context, subject string) error { |
| 101 | templateData, err := flags.ParseTemplateData(ctx) |
| 102 | if err != nil { |
| 103 | return err |
| 104 | } |
| 105 | |
| 106 | agent, err := sshutil.DialAgent() |
| 107 | if err != nil { |
| 108 | return err |
| 109 | } |
| 110 | |
| 111 | client, err := cautils.NewClient(ctx) |
| 112 | if err != nil { |
| 113 | return err |
| 114 | } |
| 115 | |
| 116 | // Check if a user key exists |
| 117 | if roots, err := client.SSHRoots(); err == nil && len(roots.UserKeys) > 0 { |
| 118 | userKeys := make([]ssh.PublicKey, len(roots.UserKeys)) |
| 119 | for i, uk := range roots.UserKeys { |
| 120 | userKeys[i] = uk.PublicKey |
| 121 | } |
| 122 | exists, err := agent.HasKeys(sshutil.WithSignatureKey(userKeys), sshutil.WithRemoveExpiredCerts(time.Now())) |
| 123 | if err != nil { |
| 124 | return err |
| 125 | } |
| 126 | if exists { |
| 127 | return nil |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | // Do login flow |
| 132 | flow, err := cautils.NewCertificateFlow(ctx) |
| 133 | if err != nil { |
| 134 | return err |
| 135 | } |
| 136 | |
| 137 | // There's not need to sanitize the principal, it should come from ssh. |
| 138 | principals := []string{subject} |
| 139 | |
| 140 | // Make sure the validAfter is in the past. It avoids `Certificate |
| 141 | // invalid: not yet valid` errors if the times are not in sync |
| 142 | // perfectly. |
| 143 | validAfter := provisioner.NewTimeDuration(time.Now().Add(-1 * time.Minute)) |
| 144 | validBefore := provisioner.TimeDuration{} |
| 145 | |
| 146 | token, err := flow.GenerateSSHToken(ctx, subject, cautils.SSHUserSignType, principals, validAfter, validBefore) |
| 147 | if err != nil { |
| 148 | return err |
| 149 | } |
| 150 | |
| 151 | // NOTE: For OIDC tokens the subject should always be the email. The |
| 152 | // provisioner is responsible for loading and setting the principals with |
| 153 | // the application of an Identity function. |
| 154 | if email, ok := tokenEmail(token); ok { |
| 155 | subject = email |
| 156 | } |
| 157 |
no test coverage detected
searching dependent graphs…