I am attempting to post to S3 from an Elm application. I have a backend service that generates the signature, policy, etc required to make the post.
I have read through the docs and many of the posts about how to post to S3 and the need to use AWS4-HMAC-SHA256, however, my code is still failing with the error.
Elixir Code to create signature
defp signature(signing_key, string_to_sign) do
hmac_sha256(signing_key, string_to_sign)
|> bytes_to_string
end
defp signing_key(secret_key, date, region) do
hmac_sha256("AWS4#{secret_key}", date)
|> hmac_sha256(region)
|> hmac_sha256(#service)
|> hmac_sha256(#aws_request)
end
def hmac_sha256(key, data) do
:crypto.hmac(:sha256, key, data)
end
def bytes_to_string(bytes) do
Base.encode16(bytes, case: :lower)
end
Elixir code to create signature
defp policy(key, mimetype, credential, date, expiration_window \\ 60) do
%{
expiration: now_plus(expiration_window),
conditions: [
%{bucket: bucket_name},
["starts-with", "$key", key],
%{acl: "public-read"},
%{success_action_status: "201"},
["starts-with", "$Content-Type", mimetype],
%{"x-amz-credential": credential},
%{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
%{"x-amz-date": date}
]
}
|> Poison.encode!
|> Base.encode64
end
Elixir code to create credential
defp credential(date) do
credential(aws_config[:access_key_id], date)
end
defp credential(key, date) do
key <> "/" <> date <> "/" <> region() <> "/" <> #service <> "/" <> #aws_request
end
Elm Code that makes post
makeMultiPart : UploadSignatureModel -> File -> Http.Body
makeMultiPart uploadSignature file =
Http.multipartBody
[ Http.stringPart "key" uploadSignature.key
, Http.stringPart "acl" uploadSignature.acl
, Http.stringPart "success_action_status" "201"
, Http.stringPart "Content-Type" uploadSignature.content_type
, Http.stringPart "X-Amz-Credential" uploadSignature.credential
, Http.stringPart "X-Amz-Algorithm" "AWS4-HMAC-SHA256"
, Http.stringPart "Policy" uploadSignature.policy
, Http.stringPart "Signature" uploadSignature.signature
, Http.stringPart "AWSAccessKeyId" uploadSignature.aws_access_key_id
, Http.filePart "file" file
]
Obviously, I am missing something but for the life of me can't figure it out.
EDIT:
The error code the user gets is this:
<Error>
<Code>InvalidRequest</Code>
<Message>The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.</Message>
<RequestId>0B1FCA2C05E910B1</RequestId>
<HostId>7ydiqVEEPu22aN+o1BJhAQDQbDXBodChOfHv7986R8ItnhQ5hv0/iETzakTH8gLVljjqKr3lIUg=</HostId>
</Error>
Related
I got this problem. Why i get this access error and how can i fix it?
Odoo Server Error - Access Error
Sorry, you are not allowed to access
this document. Only users with the following access level are
currently allowed to do that:
Administration/Settings
(Document model: ir.config_parameter) - (Operation: read, User: 21)
Here is my code:
Button submit:
<button string="Confirm" name="button_submit" states="draft" type="object" class="oe_highlight"/>
My python code:
def send_email(self, subject, message_body, email_from, email_to):
template_obj = self.env['mail.mail']
template_data = {
'subject': subject,
'body_html': message_body,
'email_from': email_from,
'email_to': email_to
}
template_id = template_obj.create(template_data)
template_obj.send(template_id)
template_id.send()
#api.multi
def request_recuitment_send_mail(self):
""" Send mail with wizard """
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
base_url += '/web#id=%d&view_type=form&model=%s' % (self.id, self._name)
subject = '''Request recuitment for {}'''.format(self.job_id.name)
message_body = '''
<div style="font-size: medium;">
Dear {},
Please check this link for more information Click here
'''.format(
self.user_id.name,
base_url,
)
email_from = '''HR Recruiment <{}>'''.format(self.approver_id.work_email)
email_to = self.user_id.email
self.send_email(subject, message_body, email_from, email_to)
#api.multi
def button_approve(self):
subject = "Request recruitment for {self.job_id.name} has been approved "
body = '''
Position Request: {}
Quantity of Position: {}
Department: {}
Expected Gross Salary: {}
'''.format(
self.job_id.name,
self.quantity,
self.department_id.name,
self.salary_cross_expected
)
self.env['mail.message'].create({'message_type': "notification",
"subtype": self.env.ref("mail.mt_comment").id,
'body': body,
'subject': subject,
'needaction_partner_ids': [(4, self.user_id.partner_id.id,)],
'model': self._name,
'res_id': self.id,
})
self.request_recuitment_approved_send_mail()
self.write({'state': 'approved'})
It should be safe to use sudo() in this case:
request.env['ir.config_parameter'].sudo().get_param('web.base.url')
"Normal" Users don't have any rights on model ir.config_parameter (System parameters). Only the admin (one of its default access groups) or the superuser can read such parameters.
About sudo([flag=True]) from the current documentation (Odoo 15):
Returns a new version of this recordset with superuser mode enabled or disabled, depending on flag. The superuser mode does not change the current user, and simply bypasses access rights checks.
IMPORTANT: I'm not completely sure when it was changed, but IIRC the "current user change" was removed since Odoo 13. So for Odoo 12 sudo will change the current user, which for example will have impacts on default values on creation, created message authors, and so on.
In your case that's irrelevant, because you're only getting the base url or the parameter value, and that's it.
I'm working with Ecto (with Postgres) for the first time and I have the following two schemas (both somewhat simplified):
defmodule RailroadServer.Database.RailroadSystem do
#moduledoc """
Schema for an entire railroad system.
"""
use Ecto.Schema
import Ecto.Changeset
alias RailroadServer.Database
schema "railroad_systems" do
field :railroad_system_name, :string
has_many :depos, Database.Depo
end
#fields ~w(railroad_system_name)a
def changeset(data, params \\ %{}) do
data
|> cast(params, #fields)
|> validate_required([:railroad_system_name])
|> validate_length(:railroad_system_name, max: 50)
end
end
defmodule RailroadServer.Database.Depo do
#moduledoc """
Schema for a node that stores trains.
"""
use Ecto.Schema
import Ecto.Changeset
alias RailroadServer.Database
schema "depos" do
field :capacity, :integer
field :depo_uuid, :string
field :depo_name, :string
belongs_to :railroad_system, Database.RailroadSystem
end
#fields ~w(capacity depo_uuid depo_name)a
def changeset(data, params \\ %{}) do
data
|> cast(params, #fields)
|> validate_required([:capacity, :depo_uuid, :depo_name])
|> validate_number(:capacity, greater_than: 0)
|> validate_length(:depo_name, max: 50)
|> validate_length(:depo_uuid, max: 50)
|> foreign_key_constraint(:railroad_system_id)
end
end
Based on these migrations:
defmodule RailroadServer.Database.Repo.Migrations.CreateRailroadSystems do
use Ecto.Migration
def change do
create table(:railroad_systems) do
add :railroad_system_name, :varchar, null: false, size: 50
end
create unique_index("railroad_systems", [:railroad_system_name])
end
end
defmodule RailroadServer.Database.Repo.Migrations.CreateDepos do
use Ecto.Migration
def change do
create table(:depos) do
add :railroad_system_id, references("railroad_systems"), null: false
add :depo_uuid, :varchar, size: 50, null: false
add :depo_name, :varchar, size: 50, null: false
add :capacity, :integer, null: false
end
create index("depos", [:railroad_system_id])
create index("depos", [:depo_uuid], unique: true)
create index("depos", [:depo_name], unique: true)
end
end
Which I'm constructing with the following code:
def insert_railway_system(system_name, depos) do
cs = %RailroadSystem{}
|> RailroadSystem.changeset(%{railroad_system_name: system_name})
|> put_assoc(:depos, create_depos(depos))
if cs.valid? do
Repo.insert(cs)
else
{:error, cs}
end
end
_ = """
Uses a list of depo nodes to construct a list of depo changeset.
"""
defp create_depos(depos) do
Enum.map(depos, fn(depo) -> Depo.changeset(%Depo{}, depo) end)
end
However, when I run this function (with data that produces a valid changeset), I get a NULL column error because the foreign key for the railway system in the depo struct doesn't exist. How do I make sure that Ecto passes that foreign key?
The output:
19:06:07.401 [debug] QUERY OK db=0.8ms
begin []
19:06:07.406 [debug] QUERY OK db=0.6ms
INSERT INTO "railroad_systems" ("railroad_system_name") VALUES ($1) RETURNING "id" ["test Can insert railway system"]
19:06:07.409 [debug] QUERY ERROR db=2.7ms
INSERT INTO "depos" ("capacity","depo_name","depo_uuid") VALUES ($1,$2,$3) RETURNING "id" [23, "A depo", "d387a91b-db77-4758-87ed-9951d5c2de8a"]
19:06:07.410 [debug] QUERY OK db=0.1ms
rollback []
1) test Can insert railway system (RailroadServer.DatabaseTest)
apps/railroad_server/test/railroad_server/database_test.exs:9
** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column "railroad_system_id" violates not-null constraint
table: depos
column: railroad_system_id
Failing row contains (3, null, d387a91b-db77-4758-87ed-9951d5c2de8a, A depo, 23).
stacktrace:
(ecto_sql) lib/ecto/adapters/sql.ex:621: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto) lib/ecto/repo/schema.ex:649: Ecto.Repo.Schema.apply/4
(ecto) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ecto) lib/ecto/association.ex:927: Ecto.Association.BelongsTo.on_repo_change/5
(ecto) lib/ecto/association.ex:413: Ecto.Association.on_repo_change/7
(elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/association.ex:392: Ecto.Association.on_repo_change/4
(ecto) lib/ecto/repo/schema.ex:811: Ecto.Repo.Schema.process_parents/4
(ecto) lib/ecto/repo/schema.ex:242: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ecto) lib/ecto/association.ex:662: Ecto.Association.Has.on_repo_change/5
(ecto) lib/ecto/association.ex:432: anonymous fn/8 in Ecto.Association.on_repo_change/7
(elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/association.ex:428: Ecto.Association.on_repo_change/7
(elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/association.ex:392: Ecto.Association.on_repo_change/4
(ecto) lib/ecto/repo/schema.ex:837: Ecto.Repo.Schema.process_children/5
(ecto) lib/ecto/repo/schema.ex:914: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto_sql) lib/ecto/adapters/sql.ex:890: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection) lib/db_connection.ex:1415: DBConnection.run_transaction/4
(railroad_server) lib/railroad_server/database.ex:61: RailroadServer.Database.insert_railway_system/4
Versions:
Elixir - 1.9.0
Ecto - 3.17
Postgrex - 0.14.3
Prosgres - 11.4
When I try an insert with identical code as in your insert_railway_system(), I do not get a NULL column error.
My schemas are similar. The only significant difference in my code is in the changeset where I have the constraint:
|> assoc_constraint()
instead of:
|> foreign_key_constraint()
But I changed my code to try the foreign_key_constraint(), leaving the argument the same, which is equivalent to your :railroad_system, and the insert still worked. The insert also worked when I did the equivalent of foreign_key_constraint(:railroad_system_id). In fact, if I use foreign_key_constraint(:hello_world), the insert still works, so as far as I can tell, the second argument to foreign_key_constraint() is ignored, which is puzzling. I even did mix ecto.reset, which deletes the repo/database, recreates the repo/database, then executes the migrations, which creates the tables in the repo/database, and I got the same results.
My "create_depos" migration has the equivalent of the following:
add :railroad_system_id, references(:railroad_systems)
Please post:
The create_depos() function (although for me just using an attributes map instead of a changeset also worked)
The full stack trace of the error.
Your migrations.
Below I have a button that attempts to load remote content ...
import Post exposing (Post)
import Html exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode
type alias Model =
{ posts : List Post }
type Msg
= Search String
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search s ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ s)
|> Http.send PostsReceived
in
( model, cmd )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]
This is a valid Elm program, only there's one little problem: The API doesn't allow me to search by string. This is not allowed
/posts?author=amelia => Malformed Request Error
However, this is allowed
/posts?author=2 => [ {...}, {...}, ... ]
So I must first fetch an author to get his/her id, and then I can fetch posts using the author's id...
/author?name=amelia => { id: 2, name: "amelia", ... }
/posts?author=2
How can I sequence one request after the next? Ideally I'd like to cache the authors somewhere in the model so we're only requesting ones that we haven't seen before.
You can use Task.andThen to chain two tasks together. Assuming that the /posts response includes the author ID, you can then add that author ID into you model when you handle the response.
Search s ->
let
getAuthor =
Author.decode
|> Http.get ("/author?name=" ++ s)
|> Http.toTask
getPosts author =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ author.id)
|> Http.toTask
cmd =
getAuthor
|> Task.andThen getPosts
|> Task.attempt PostsReceived
in
( model, cmd )
I've got this compiling at https://ellie-app.com/DBJc6Kn3G6a1 if that helps
You can chain together tasks using Task.andThen. You'll first have to convert the web requests to tasks using Http.toTask:
postsByAuthorName : String -> Cmd Msg
postsByAuthorName name =
Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int)
|> Http.toTask
|> Task.andThen (\id ->
Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost)
|> Http.toTask)
|> Task.attempt PostsReceived
A a dictionary and a couple more Msg options should do it.
You'll have to write the decoder for the Author response, but other than that this should work
type alias Model =
{ posts : List Post
, authors : Dict String Int }
type Msg
= Search String
| SearchAuthor String
| AuthorReceived (Result Http.Error Int String)
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search author ->
case (Dict.get author model.authors) of
Nothing ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/author?name=" ++ author)
|> Http.send AuthorReceived
in
(model,cmd)
Just num ->
let
cmd =
(Decode.list Author.decode)
|> Http.get ("/posts?author=" ++ num)
|> Http.send PostsReceived
in
( model, cmd )
AuthorReceived (Ok number name) ->
let
updatedAuthors = Dict.inster name number model.authors
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ number)
|> Http.send PostsReceived
in
{model | authors = updatedAuthors } ! [cmd]
AuthorReceived (Err error) ->
(mode, Cmd.none )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]
I'm struggling for a while to make Grafana LDAP work as I can't find appropriate search filter. In AD, both groups Grafana-Admin/User have a group as a member and that group have users which need to authenticate to Grafana.
To simplify, my user sys22 is in a group called Graylog, group Graylog is a Member Of group Grafana. And, I want to use group Grafana in LDAP configuration.
verbose_logging = true
[[servers]]
host = "dc-01.corp.domain.com"
port = 389
use_ssl = false
ssl_skip_verify = true
bind_dn = "CN=Grafana-Auth,OU=ApplicationAccount,OU=SE,OU=Admin,DC=corp,DC=domain,DC=com"
bind_password = 'pass1'
search_filter = "(&(objectCategory=Person)(sAMAccountName=%s)"
search_base_dns = ["dc=corp,dc=domain,dc=com"]
# group_search_filter = "(member:1.2.840.113556.1.4.1941:=%s)"
# group_search_filter_user_attribute = "distinguishedName"
# group_search_base_dns =
["OU=Group,OU=SE,OU=Unit,DC=corp,DC=domain,DC=com"]
[servers.attributes]
name = "givenName"
surname = "sn"
username = "sAMAccountName"
member_of = "distinguisedName"
email = "mail"
[[servers.group_mappings]]
group_dn = "CN=Grafana-
Admin,OU=Access,OU=Group,OU=SE,OU=Unit,DC=corp,DC=domain,DC=com"
org_role = "Admin"
[[servers.group_mappings]]
group_dn = "CN=Grafana-
User,OU=Access,OU=Group,OU=SE,OU=Unit,DC=corp,DC=domain,DC=com"
org_role = "Editor"
[[servers.group_mappings]]
group_dn = "*"
org_role = "Viewer"
Applying various filters doesn't help and all the time I am getting
lvl=eror msg="Invalid username or password" logger=context userId=0 orgId=0
uname= error="Invalid Username or Password"
t=2018-05-18T08:01:02+0200 lvl=info msg="Request Completed" logger=context
userId=0 orgId=0 uname= method=POST path=/login status=401
remote_addr=X.X.X.X time_ms=13 size=98
referer=http://graylogprod.corp.domain.com/grafana/login
Any advice I'll much appreciate...
Thank you,
B
An issue in my case was in the infrastructure of the AD. Grafana doesn't support nested groups and users couldn't be found.
I'm using Elm Form https://github.com/etaque/elm-form, but I can't figure out the validations of two fields, I want to validate the password and password confirmation fields match.
This is what I have so far:
validate : Validation String RegUser
validate =
map6 RegUser
(field "email" email)
(field "password" (string |> andThen nonEmpty))
(field "passwordConfirmation" (string |> andThen nonEmpty))
(field "firstName" (string |> defaultValue ""))
(field "lastName" (string |> defaultValue ""))
(field "companyName" (string |> defaultValue ""))
The whole code: https://github.com/werner/madison-elm/blob/master/src/elm/Components/Register/Models.elm
Thanks for any help.
Any time you see packages that expose andThen, succeed, and fail functions, that's a good indication that you can "peel apart" the value to inspect and bind its value with another function. In this case, we can use andThen twice to build up a validation function that peeks inside two named fields and checks that they match:
matchingFields : String -> String -> Validation String String
matchingFields masterField confirmField =
field masterField string
|> andThen (\masterVal -> field confirmField string
|> andThen (\confirmVal ->
if masterVal == confirmVal then
succeed masterVal
else
fail (customError "Values do not match")))
You can then use it in your overall validation function like this:
validate : Validation String RegUser
validate =
map6 RegUser
(field "email" email)
(matchingFields "password" "passwordConfirmation" |> andThen nonEmpty)
(field "passwordConfirmation" (string |> andThen nonEmpty))
...
The solution was close to the one provided by Chad, based on https://github.com/etaque/elm-form/issues/75#issuecomment-269861043:
validate : Validation TranslationId RegUser
validate =
map6 RegUser
(field "email" email)
(field "password" (string |> andThen nonEmpty))
((field "password" string) |> andThen validateConfirmation)
(field "firstName" (string |> defaultValue ""))
(field "lastName" (string |> defaultValue ""))
(field "companyName" (string |> defaultValue ""))
validateConfirmation : String -> Validation TranslationId String
validateConfirmation password =
field "passwordConfirmation"
(string
|> andThen
(\confirmation ->
if password == confirmation then
succeed confirmation
else
fail (customError PasswordNotMatch)
)
)