Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -f/--credentials-file option #62

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
- Breaking: Data.Docker.Nix.FetchDocker.inheritAdapter no longer
supports dynamic keys because Nix-Expr-Types.Binding.Inherit
no longer supports them as of hnix-0.15.
- Support hnix-0.15 and hnix-0.16.
- Support hnix-0.15, hnix-0.16, and hnix-0.17.
- Support and require optparse-generic-1.4.0 or higher.
- Support turtle-1.6
- Support turtle-1.6 and turtle
- Add the `--credentials-file` option to allow passing credentials as a file.

## 1.0.7
### Changed
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ request to the public docker hub registry, in which case they ask for a
short-lived authentication token from the registry auth server and then make the
request to the public docker hub registry.

Both types of credential may instead be passed as file using `--credential-file`.
The credential file should contain either:
```
USERNAME=<username>
PASSWORD=<password>
```
or
```
BEARER_TOKEN=<token>
```

## How to build

Building (and developing a patch for) this project using `cabal` is
Expand Down
19 changes: 16 additions & 3 deletions hocker-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ docker registry.
```shell
Fetch a docker image config JSON from the registry

Usage: hocker-config [--registry URI] ([-u|--username BASIC USERNAME]
[-p|--password BASIC PASSWORD] | [-t|--token BEARER TOKEN])
Usage: hocker-config [--registry URI]
[(-u|--username BASIC USERNAME)
(-p|--password BASIC PASSWORD) |
(-t|--token BEARER TOKEN) | (-f|--credentials-file PATH)]
[--out STRING] IMAGE-NAME IMAGE-TAG

Available options:
Expand All @@ -18,7 +20,18 @@ Available options:
-p,--password BASIC PASSWORD
Password part of a basic auth credential
-t,--token BEARER TOKEN Bearer token retrieved from a call to `docker login`
(mutually exclusive to --username and --password)
(mutually exclusive to --username and --password and --credentials-file)
-f,--credentials-file PATH
Path to a file containing either:

USERNAME=<username>
PASSWORD=<password>

or

BEARER_TOKEN=<token>

(mutually exclusive to --username and --password and --token)
--out STRING Write content to location
IMAGE-NAME Docker image name, e.g: 'debian' in debian:jessie
IMAGE-TAG Docker image tag identifier, e.g: 'jessie' in
Expand Down
19 changes: 16 additions & 3 deletions hocker-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
```shell
Fetch a docker image from a docker registry without using docker

Usage: hocker-image [--registry URI] ([-u|--username BASIC USERNAME]
[-p|--password BASIC PASSWORD] | [-t|--token BEARER TOKEN])
Usage: hocker-image [--registry URI]
[(-u|--username BASIC USERNAME)
(-p|--password BASIC PASSWORD) |
(-t|--token BEARER TOKEN) | (-f|--credentials-file PATH)]
[--out STRING] IMAGE-NAME IMAGE-TAG

Available options:
Expand All @@ -17,7 +19,18 @@ Available options:
-p,--password BASIC PASSWORD
Password part of a basic auth credential
-t,--token BEARER TOKEN Bearer token retrieved from a call to `docker login`
(mutually exclusive to --username and --password)
(mutually exclusive to --username and --password and --credentials-file)
-f,--credentials-file PATH
Path to a file containing either:

USERNAME=<username>
PASSWORD=<password>

or

BEARER_TOKEN=<token>

(mutually exclusive to --username and --password and --token)
--out STRING Write content to location
IMAGE-NAME Docker image name, e.g: 'debian' in debian:jessie
IMAGE-TAG Docker image tag identifier, e.g: 'jessie' in
Expand Down
22 changes: 17 additions & 5 deletions hocker-layer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
```shell
Fetch a docker image layer from a docker registry without using docker

Usage: hocker-layer [--registry URI] ([-u|--username BASIC USERNAME]
[-p|--password BASIC PASSWORD] | [-t|--token BEARER TOKEN])
Usage: hocker-layer [--registry URI]
[(-u|--username BASIC USERNAME)
(-p|--password BASIC PASSWORD) |
(-t|--token BEARER TOKEN) | (-f|--credentials-file PATH)]
[--out STRING] (-l|--layer SHA256) IMAGE-NAME IMAGE-TAG

Available options:
Expand All @@ -17,10 +19,20 @@ Available options:
-p,--password BASIC PASSWORD
Password part of a basic auth credential
-t,--token BEARER TOKEN Bearer token retrieved from a call to `docker login`
(mutually exclusive to --username and --password)
(mutually exclusive to --username and --password and --credentials-file)
-f,--credentials-file PATH
Path to a file containing either:

USERNAME=<username>
PASSWORD=<password>

or

BEARER_TOKEN=<token>

(mutually exclusive to --username and --password and --token)
--out STRING Write content to location
-l,--layer SHA256 Layer to fetch, by hash digest (unprefixed by the
hash algorithm identifier)
-l,--layer SHA256 Hash digest of layer to fetch
IMAGE-NAME Docker image name, e.g: 'debian' in debian:jessie
IMAGE-TAG Docker image tag identifier, e.g: 'jessie' in
debian:jessie
Expand Down
23 changes: 17 additions & 6 deletions hocker-manifest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ specification.
## Quickstart

```shell
Pull a docker image manifest from the registry

Usage: hocker-manifest [--registry URI] ([-u|--username BASIC USERNAME]
[-p|--password BASIC PASSWORD] |
[-t|--token BEARER TOKEN]) [--out STRING] IMAGE-NAME
Usage: hocker-manifest [--registry URI]
[(-u|--username BASIC USERNAME)
(-p|--password BASIC PASSWORD) |
(-t|--token BEARER TOKEN) |
(-f|--credentials-file PATH)] [--out STRING] IMAGE-NAME
IMAGE-TAG

Available options:
Expand All @@ -24,7 +24,18 @@ Available options:
-p,--password BASIC PASSWORD
Password part of a basic auth credential
-t,--token BEARER TOKEN Bearer token retrieved from a call to `docker login`
(mutually exclusive to --username and --password)
(mutually exclusive to --username and --password and --credentials-file)
-f,--credentials-file PATH
Path to a file containing either:

USERNAME=<username>
PASSWORD=<password>

or

BEARER_TOKEN=<token>

(mutually exclusive to --username and --password and --token)
--out STRING Write content to location
IMAGE-NAME Docker image name, e.g: 'debian' in debian:jessie
IMAGE-TAG Docker image tag identifier, e.g: 'jessie' in
Expand Down
31 changes: 28 additions & 3 deletions src/Hocker/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
module Hocker.Types where

import Control.Applicative
import qualified Options.Applicative.Help.Pretty as Doc
import Control.Monad.Error.Class
import qualified Control.Monad.Except as Except
import Control.Monad.IO.Class
Expand Down Expand Up @@ -151,12 +152,16 @@ newtype Base32Digest = Base32Digest Text
newtype Base16Digest = Base16Digest Text
deriving (Show, Read, Eq)

data Credentials = Basic Username Password | BearerToken Text
data Credentials = Basic Username Password | BearerToken Text | CredentialsFile FilePath
deriving (Show)

instance ParseField Credentials where
readField = Options.readerError "Internal, fatal error: unexpected use of readField"
parseField _help _long _short _value = (Basic <$> parseUsername <*> parsePassword) <|> (BearerToken <$> parseToken)
parseField _help _long _short _value =
( (Basic <$> parseUsername <*> parsePassword)
<|> (BearerToken <$> parseToken)
<|> (CredentialsFile <$> parseCredentialFile)
)
where
parseUsername = Text.pack <$>
(Options.option Options.str $
Expand All @@ -179,9 +184,29 @@ instance ParseField Credentials where
( Options.metavar "BEARER TOKEN"
<> Options.long "token"
<> Options.short 't'
<> Options.help "Bearer token retrieved from a call to `docker login` (mutually exclusive to --username and --password)"
<> Options.helpDoc (Just $ Doc.vcat
[ "Bearer token retrieved from a call to `docker login`"
, "(mutually exclusive to --username and --password and --credentials-file)"
])
)
)
parseCredentialFile = Options.option Options.str $
( Options.metavar "PATH"
<> Options.long "credentials-file"
<> Options.short 'f'
<> Options.helpDoc (Just $ Doc.vcat
[ "Path to a file containing either:"
, ""
, "USERNAME=<username>"
, "PASSWORD=<password>"
, ""
, "or"
, ""
, "BEARER_TOKEN=<token>"
, ""
, "(mutually exclusive to --username and --password and --token)"
])
)

instance ParseFields Credentials
instance ParseRecord Credentials where
Expand Down
47 changes: 38 additions & 9 deletions src/Network/Wreq/Docker/Registry.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

-----------------------------------------------------------------------------
-- |
Expand All @@ -24,6 +25,7 @@

module Network.Wreq.Docker.Registry where

import qualified Control.Exception as Exception
import Control.Lens
import qualified Control.Monad.Except as Except
import Control.Monad.Reader
Expand All @@ -34,9 +36,13 @@ import qualified Data.ByteString.Char8 as C8
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import URI.ByteString
import NeatInterpolation
import Data.Bifunctor
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import qualified Network.Wreq as Wreq
import qualified Turtle
import System.Directory
import qualified System.IO

import Data.Docker.Image.Types
import Hocker.Lib
Expand Down Expand Up @@ -76,12 +82,14 @@ mkAuth :: RegistryURI -- ^ Docker registry
-> ImageName -- ^ Docker image name
-> Maybe Credentials -- ^ Docker registry authentication credentials
-> IO (Maybe Wreq.Auth)
mkAuth reg (ImageName img) credentials =
mkAuth reg iname@(ImageName img) credentials =
case credentials of
Just (BearerToken token)
-> pure (Just $ Wreq.oauth2Bearer (encodeUtf8 token))
Just (Basic username password)
-> pure (Just $ Wreq.basicAuth (encodeUtf8 username) (encodeUtf8 password))
Just (CredentialsFile path)
-> parseCredentialsFile path >>= mkAuth reg iname . Just
Nothing | reg /= defaultRegistry
-> pure Nothing
| otherwise
Expand All @@ -90,6 +98,27 @@ mkAuth reg (ImageName img) credentials =
getHubToken = Wreq.get ("https://auth.docker.io/token?service=registry.docker.io&scope=repository:"<>img<>":pull")
mkHubBearer rsp = (Wreq.oauth2Bearer . encodeUtf8) <$> (rsp ^? Wreq.responseBody . key "token" . _String)

parseCredentialsFile :: FilePath -> IO Credentials
parseCredentialsFile path = do
let parse = do
kvs <- Text.readFile path
<&> fmap (second (Text.drop 1) . Text.break (== '=')) . Text.lines
pure $ case kvs of
[(k,v)] | k == "BEARER_TOKEN", v /= "" -> Just $ BearerToken v
[(k1,v1),(k2,v2)] | k1 == "USERNAME", v1 /= "", k2 == "PASSWORD", v2 /= "" -> Just $ Basic v1 v2
[(k1,v1),(k2,v2)] | k2 == "USERNAME", v2 /= "", k1 == "PASSWORD", v1 /= "" -> Just $ Basic v2 v1
_ -> Nothing

creds <- parse `Exception.catch` \(e :: Exception.IOException) -> do
System.IO.hPutStrLn System.IO.stderr "error: while trying to read credentials file..."
Exception.throwIO e
case creds of
Just val -> pure val
Nothing -> do
System.IO.hPutStrLn System.IO.stderr "error: could not parse credentials file"
Turtle.exit (Turtle.ExitFailure 1)


-- | Retrieve a list of layer hash digests from a docker registry
-- image manifest JSON.
--
Expand Down
Loading