Autentykacja na poziomie bazy

Witam,

Dostałem zlecenie w firmie na stworzenie aplikacji do użytku wewnętrznego, niewielki projekt. Sprawa od razu rozbiła się o autentykacje, na której implementacje nie mam pojęcia bo troche odbiega od utartych schematów (przynajmniej tych z tutoriali:) ). Wszystkie inne aplikacje w firmie (php) autentykują użytkowników na podstawie praw do bazy danych tj. użytkownik i hasło a być może poźniej obsługiwany jest poziom praw, chociaż tym na razie się nie interesuje.

Czy ktoś ma pomysł jak to zrealizować w Railsach?

Pozdrawiam

first try:

ActiveRecord.establish_connection na każdym requeście. Przy takim ruchu nie powinno być problemów.

Yhy, to jest nawet nawet sposób, przetestowałem i może się udać.
Chociaż myślałem ze po autentykacji tym sposobem zapisze sobie tego użytkownika do swojej bazy i dalej już będę z nią pracował.

a ja bym się najpierw zastanowił, czy to, że wszystkie aplikacje w firmie tak działają, jest wyznacznikiem tego, czy to jest dobre rozwiązanie i powinieneś pakować się w takie kłopoty.

Dlaczego miało by być złe i o jakich kłopotach mowa?

no właśnie?

generalnie jedynym kłopotem moze być liczba połączeń do bazy, oraz fakt że zestawianie połączenia często chwilę trwa.

Pod innymi względami rozwiązanie jeden uźytkoenik aplikacji = jeden użytkownik bazy jest sensowne bardzo.

ja uważam to za zło:

  1. co by nie mówić, railsy (jak i za pewne większość innych frameworków) słabo jest przystosowane do tego typu uwierzytelniania.
  2. implementacja autoryzacji jest słaba.
  3. wspomniana przez świstaka liczba połączeń + czas zestawienia połączenia.
  4. kompletny brak kontroli nad uwierzytelnianiem na poziomie aplikacji (istnieje scenariusz, gdy wszyscy mają dostęp do wszystkiego, bo ktoś przypadkiem wywalił użytkowników, i dał im standardowy(pełny) dostęp)

Nie wiem czy do konca o to ci chodzi, ale kombinowalbym z cancan’em (najwyzej cache’owal troche ), cos moze w style :

[code=ruby]class UserAbility
include CanCan::Ability

def initialize(current_user = nil)

@current_user = current_user || User.new

grants = ActiveRecord::Base.connection.execute("SHOW GRANTS FOR #{ @current_user.mysql_name }@localhost")

can :read, Tasks if grants.to_a.any? {|w| w[0] =~ /GRANT (USAGE|SELECT) ON `db_name`.`tasks` TO 'bob_example'@'localhost'/} 

end[/code]

@Athril - co imo potwierdza mój #2

[quote=krzyzak]1. co by nie mówić, railsy (jak i za pewne większość innych frameworków) słabo jest przystosowane do tego typu uwierzytelniania.
3. wspomniana przez świstaka liczba połączeń + czas zestawienia połączenia.[/quote]
W pełni się podpisuję pod oboma z tych punktów.
Implementacja autentykacji po stronie aplikacji (lub, jeśli ma to być zewnętrzna usługa, to co najmniej LDAP) jest standardem nie bez powodu.

Autentykacja jednego requesta jest prosta: user podaje login i hasło, serwer nawiązuje połączenie z bazą z tymi danymi, wykonuje odpowiednie query i zwraca rezultat.

Jeśli jednak user chce zrobić coś w następnym requeście? Normalne systemy tworzą secure cookie i na jego podstawie autoryzują kolejne requesty.

Przy autoryzacji w oparciu o bazę danych niestety trzeba za każdym razem podawać login usera i hasło. Czyli musi ono być gdzieś przechowywane, ewentualnie user musi do każdego requestu je podać. Naturalny sposób przechowywania to sesja. Tyle, że sesja w Rails jest domyślnie trzymana w cookie. Czyli login i hasło użytkownika wędrują sobie dzielnie pomiędzy przeglądarką i serwerem w każdym requeście. Głupota i brak bezpieczeństwa.

Tak, wiem przekonałem się po godzinach kopania że railsy nie przewidują czegoś takiego.

Jednak mimo wszystko spróbowałem - pomysł był taki żeby aplikacja łączyła się na swoich uprawnieniach i żeby tak zostało przez cały okres jej pracy - czyli standard, test na dostęp do bazy odbywałby się tylko przy logowaniu, później taki delikwent byłby zapisywany do bazy - reszta interakcji odbywała by się w standardowy sposób.

[code=ruby] def authenticate(user,password)
begin
connection = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.new(nil, nil, [“host”, 5432, nil, nil, “nazwa_bazy”, user, password], {})

rescue PGError
#FAILED
redirect_to root_path
return
end

#SUCCESS
connection.disconnect! unless connection.nil?
redirect_to orders_path

end[/code]
Zakładając że to działa zgodnie założeniami + fakt ze to tylko w sieci lokalnej właściwie wszystkie w/w punkty nie mają zastosowania - prawie wszystkie, bo zostaje słaba implementacja :confused:

Zbadam jeszcze LDAP, zdaje się ze działa w sieci. Znacie jakieś gemy do tego? Widzę ze AuthLogic niby ma plugin LDAP, ale “under development”.

Podejscie dzieki ktoremu autor mogl napisac ta ksiazke

Nie zrozumiałeś, miałem na myśli punkt o czasie połączenia.

W takim razie zapytam inaczej.

Na serwerze na którym będzie chodzić ta aplikacja nie będzie dostępu do roota, to jasne. Na serwerze działa LDAP, nie wiem dokładnie ale czy żeby uwierzytelnić użytkownika tez nie jest potrzebne hasło admina? w każdym razie nie będę go miał. Każdy użytkownik ma konto na tym serwerze, więc można by jeszcze ewentualnie użyć PAMa, ale jedyny gem na który się natknąłem do tego, nie jest ukończony.

Mając do dyspozycji w/w usługi jak byście uwierzytelniali?

Ok, problem się rozwiązał.
Skończyło się na autentykacji PAM z backendem LDAPa.

O WIELE lepsze rozwiązanie niż autentykacja przez bazę. Powodzenia zatem :slight_smile: