Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117754045
kolab_api_controller.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
16 KB
Referenced Files
None
Subscribers
None
kolab_api_controller.php
View Options
<?php
/*
+--------------------------------------------------------------------------+
| This file is part of the Kolab Web Admin Panel |
| |
| Copyright (C) 2011-2012, Kolab Systems AG |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
| Author: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* Main controller class to serve the Kolab Admin API
*/
class
kolab_api_controller
{
public
$output
;
private
$config
;
private
$uid
;
private
$request
=
array
();
private
$services
=
array
();
private
static
$translation
=
array
();
public
function
__construct
()
{
$this
->
output
=
new
kolab_json_output
();
$this
->
config
=
Conf
::
get_instance
();
// TODO: register services based on config or whatsoever
$this
->
add_service
(
'domain'
,
'kolab_api_service_domain'
);
$this
->
add_service
(
'domain_types'
,
'kolab_api_service_domain_types'
);
$this
->
add_service
(
'domains'
,
'kolab_api_service_domains'
);
$this
->
add_service
(
'form_value'
,
'kolab_api_service_form_value'
);
$this
->
add_service
(
'group'
,
'kolab_api_service_group'
);
$this
->
add_service
(
'group_types'
,
'kolab_api_service_group_types'
);
$this
->
add_service
(
'groups'
,
'kolab_api_service_groups'
);
$this
->
add_service
(
'ou'
,
'kolab_api_service_ou'
);
$this
->
add_service
(
'ou_types'
,
'kolab_api_service_ou_types'
);
$this
->
add_service
(
'ous'
,
'kolab_api_service_ous'
);
$this
->
add_service
(
'resource'
,
'kolab_api_service_resource'
);
$this
->
add_service
(
'resource_types'
,
'kolab_api_service_resource_types'
);
$this
->
add_service
(
'resources'
,
'kolab_api_service_resources'
);
$this
->
add_service
(
'sharedfolder'
,
'kolab_api_service_sharedfolder'
);
$this
->
add_service
(
'sharedfolder_types'
,
'kolab_api_service_sharedfolder_types'
);
$this
->
add_service
(
'sharedfolders'
,
'kolab_api_service_sharedfolders'
);
$this
->
add_service
(
'roles'
,
'kolab_api_service_roles'
);
$this
->
add_service
(
'role'
,
'kolab_api_service_role'
);
$this
->
add_service
(
'role_types'
,
'kolab_api_service_role_types'
);
$this
->
add_service
(
'type'
,
'kolab_api_service_type'
);
$this
->
add_service
(
'user'
,
'kolab_api_service_user'
);
$this
->
add_service
(
'user_types'
,
'kolab_api_service_user_types'
);
$this
->
add_service
(
'users'
,
'kolab_api_service_users'
);
}
/**
* Register a class that serves a particular backend service
*/
public
function
add_service
(
$service
,
$handler
)
{
if
(
$this
->
services
[
$service
])
{
Log
::
warning
(
"Service $service is already registered"
);
return
false
;
}
$this
->
services
[
$service
]
=
$handler
;
}
/**
* Getter for a certain service object
*/
public
function
get_service
(
$service
)
{
Log
::
debug
(
"Obtaining service: $service"
);
// we are the system!
if
(
$service
==
'system'
)
{
return
$this
;
}
if
(
$handler
=
$this
->
services
[
$service
])
{
if
(
is_string
(
$handler
))
{
$handler
=
$this
->
services
[
$service
]
=
new
$handler
(
$this
);
}
if
(
is_a
(
$handler
,
'kolab_api_service'
))
{
return
$handler
;
}
}
throw
new
Exception
(
"Unknown service"
,
400
);
}
/**
* Getter for the authenticated user (ID)
*/
public
function
get_uid
()
{
return
$this
->
uid
;
}
/**
* Process the request and dispatch it to the requested service
*/
public
function
dispatch
(
$postdata
)
{
if
(!
empty
(
$_GET
[
'service'
]))
{
if
(!
empty
(
$_GET
[
'method'
]))
{
$this
->
request
=
array
(
'service'
=>
$_GET
[
'service'
],
'method'
=>
$_GET
[
'method'
]
);
}
else
{
throw
new
Exception
(
"Unknown method "
.
$_GET
[
'method'
],
400
);
}
}
else
{
throw
new
Exception
(
"Unknown service "
.
$_GET
[
'service'
],
400
);
}
// Use proxy
if
(
empty
(
$_GET
[
'proxy'
])
&&
(
$url
=
$this
->
config
->
get
(
'kolab_wap'
,
'api_url'
)))
{
$this
->
proxy
(
$postdata
,
$url
);
return
;
}
$service
=
$this
->
request
[
'service'
];
$method
=
$this
->
request
[
'method'
];
Log
::
debug
(
"Calling $service.$method"
);
// Decode request data
$postdata
=
@
json_decode
(
$postdata
,
true
);
kolab_json_output
::
decode
(
$postdata
);
// validate user session
if
(!
in_array
(
$method
,
array
(
'quit'
,
'authenticate'
)))
{
if
(!
$this
->
session_validate
(
$postdata
))
{
throw
new
Exception
(
"Invalid session"
,
403
);
}
}
// init localization
$this
->
locale_init
();
// call service method
$service_handler
=
$this
->
get_service
(
$service
);
// get only public methods
$service_methods
=
get_class_methods
(
$service_handler
);
if
(
in_array
(
$method
,
$service_methods
))
{
$result
=
$service_handler
->
$method
(
$_GET
,
$postdata
);
}
else
if
(
in_array
(
$service
.
"_"
.
$method
,
$service_methods
))
{
$call_method
=
$service
.
"_"
.
$method
;
$result
=
$service_handler
->
$call_method
(
$_GET
,
$postdata
);
}
else
{
throw
new
Exception
(
"Unknown method"
,
405
);
}
// send response
if
(
$result
!==
false
)
{
$this
->
output
->
success
(
$result
);
}
else
{
$this
->
output
->
error
(
"Internal error"
,
500
);
}
}
/**
* Proxies request to the API host
*/
private
function
proxy
(
$postdata
,
$url
)
{
$service
=
$this
->
request
[
'service'
];
$method
=
$this
->
request
[
'method'
];
$url
=
rtrim
(
$url
,
'/'
)
.
'/'
.
$service
.
'.'
.
$method
;
Log
::
debug
(
"Proxying: $url"
);
$request
=
new
HTTP_Request2
();
$url
=
new
Net_URL2
(
$url
);
$method
=
strtoupper
(
$_SERVER
[
'REQUEST_METHOD'
]);
$get
=
array
(
'proxy'
=>
1
);
// Prevent from infinite redirect
$request
->
setMethod
(
$method
==
'GET'
?
HTTP_Request2
::
METHOD_GET
:
HTTP_Request2
::
METHOD_POST
);
$request
->
setHeader
(
'X-Session-Token'
,
kolab_utils
::
get_request_header
(
'X-Session-Token'
));
kolab_client_api
::
configure
(
$request
);
if
(
$method
==
'GET'
)
{
parse_str
(
$_SERVER
[
'QUERY_STRING'
],
$query
);
unset
(
$query
[
'service'
]);
unset
(
$query
[
'method'
]);
$query
=
array_map
(
'urldecode'
,
$query
);
$get
=
array_merge
(
$query
,
$get
);
}
else
{
$request
->
setBody
(
$postdata
);
}
try
{
$url
->
setQueryVariables
(
$get
);
$request
->
setUrl
(
$url
);
$response
=
$request
->
send
();
}
catch
(
Exception
$e
)
{
$this
->
output
->
error
(
"Internal error"
,
500
);
}
try
{
$body
=
$response
->
getBody
();
}
catch
(
Exception
$e
)
{
$this
->
output
->
error
(
"Internal error"
,
500
);
}
header
(
"Content-Type: application/json"
);
echo
$body
;
exit
;
}
/**
* Validate the submitted session token
*/
private
function
session_validate
(
$postdata
)
{
if
(!
empty
(
$postdata
[
'session_token'
]))
{
$sess_id
=
$postdata
[
'session_token'
];
}
else
{
$sess_id
=
kolab_utils
::
get_request_header
(
'X-Session-Token'
);
}
if
(
empty
(
$sess_id
))
{
return
false
;
}
session_id
(
$sess_id
);
session_start
();
if
(
empty
(
$_SESSION
[
'user'
])
||
!
is_a
(
$_SESSION
[
'user'
],
'User'
)
||
!
$_SESSION
[
'user'
]->
authenticated
())
{
return
false
;
}
// Session timeout
$timeout
=
$this
->
config
->
get
(
'kolab_wap'
,
'session_timeout'
);
if
(
$timeout
&&
$_SESSION
[
'time'
]
&&
$_SESSION
[
'time'
]
<
time
()
-
$timeout
)
{
return
false
;
}
// update session time
$_SESSION
[
'time'
]
=
time
();
return
true
;
}
/* ======== system.* method handlers ======== */
/**
* Authenticate a user with the given credentials
*
* @param array GET request parameters
* @param array POST data
*
* @param array|false Authentication result
*/
private
function
authenticate
(
$request
,
$postdata
)
{
Log
::
trace
(
"Authenticating user: "
.
$postdata
[
'username'
]);
// destroy old session
if
(
$this
->
session_validate
(
$postdata
))
{
session_destroy
();
}
session_start
();
$_SESSION
[
'user'
]
=
new
User
();
$attributes
=
null
;
$password
=
$postdata
[
'password'
];
$username
=
trim
(
$postdata
[
'username'
]);
$domain
=
trim
(
$postdata
[
'domain'
]);
// find user domain
if
(
empty
(
$domain
))
{
Log
::
debug
(
"No login domain specified. Attempting to derive from username."
);
if
(
count
(
explode
(
'@'
,
$username
))
==
2
)
{
$login
=
explode
(
'@'
,
$username
);
$username
=
array_shift
(
$login
);
$domain
=
array_shift
(
$login
);
}
else
{
Log
::
debug
(
"No domain name space in the username, using the primary domain"
);
$domain
=
$this
->
config
->
get
(
'kolab'
,
'primary_domain'
);
}
}
// user info requested (it's not possible to get manager info)
if
(
$postdata
[
'info'
]
&&
(
strtolower
(
$username
)
!=
'cn=directory manager'
))
{
$service
=
$this
->
get_service
(
'user'
);
$attributes
=
$service
->
object_attributes
(
'user'
);
}
// authenticate
$user_dn
=
$_SESSION
[
'user'
]->
authenticate
(
$username
,
$password
,
$domain
,
$attributes
);
// start new (PHP) session
if
(
$user_dn
)
{
$_SESSION
[
'time'
]
=
time
();
$result
=
array
(
'user'
=>
$_SESSION
[
'user'
]->
get_username
(),
'userid'
=>
$_SESSION
[
'user'
]->
get_userid
(),
'domain'
=>
$_SESSION
[
'user'
]->
get_domain
(),
'session_token'
=>
session_id
(),
);
if
(!
empty
(
$attributes
))
{
$attributes
=
array
(
$user_dn
=>
$attributes
);
$result
[
'info'
]
=
$service
->
parse_result_attributes
(
'user'
,
$attributes
);
}
return
$result
;
}
return
false
;
}
/**
* Provide a list of capabilities the backend provides to the current user
*
* @param array GET request parameters
* @param array POST data
*
* @param array Capabilities indexed by domain name
*/
private
function
capabilities
(
$request
,
$postdata
)
{
$result
=
array
();
$domains
=
array
();
// specified domain
if
(!
empty
(
$request
[
'domain'
]))
{
$domains
[]
=
$request
[
'domain'
];
}
// get all domains
else
{
$auth
=
Auth
::
get_instance
();
// Get the domain name attribute
$dna
=
$this
->
config
->
get
(
'ldap'
,
'domain_name_attribute'
);
if
(
empty
(
$dna
))
{
$dna
=
'associateddomain'
;
}
$_domains
=
$auth
->
list_domains
();
$domains
=
$_domains
[
'list'
];
foreach
(
$domains
as
$idx
=>
$attrs
)
{
$domains
[
$idx
]
=
is_array
(
$attrs
)
?
(
is_array
(
$attrs
[
$dna
])
?
$attrs
[
$dna
][
0
]
:
$attrs
[
$dna
])
:
$attrs
;
}
// Should we have no permissions to list domain name spaces,
// we should always return our own.
if
(
count
(
$domains
)
<
1
)
{
$domains
[]
=
$_SESSION
[
'user'
]->
get_domain
();
}
}
foreach
(
$domains
as
$domain_name
)
{
// define our very own capabilities
$actions
=
array
(
'system.quit'
=>
array
(
'type'
=>
'w'
),
'system.configure'
=>
array
(
'type'
=>
'w'
),
);
foreach
(
$this
->
services
as
$sname
=>
$handler
)
{
$service
=
$this
->
get_service
(
$sname
);
foreach
(
$service
->
capabilities
(
$domain_name
)
as
$method
=>
$type
)
{
$actions
[
"$sname.$method"
]
=
array
(
'type'
=>
$type
);
}
}
$result
[
$domain_name
]
=
array
(
'actions'
=>
$actions
);
}
return
array
(
'list'
=>
$result
,
'count'
=>
count
(
$result
),
);
}
private
function
get_domain
()
{
return
array
(
'domain'
=>
$_SESSION
[
'user'
]->
get_domain
());
}
/**
* End the current user session
*
* @return bool
*/
private
function
quit
()
{
@
session_destroy
();
return
true
;
}
/**
* Session domain change
*
* @param array $request GET request parameters
*
* @return bool|array Domain attributes or False on failure
*/
private
function
select_domain
(
$request
)
{
if
(!
empty
(
$request
[
'domain'
])
&&
is_string
(
$request
[
'domain'
]))
{
if
(
$_SESSION
[
'user'
]->
set_domain
(
$request
[
'domain'
]))
{
$service
=
$this
->
get_service
(
'domain'
);
$domain
=
$service
->
domain_info
(
array
(
'id'
=>
$request
[
'domain'
]),
null
);
return
$domain
;
}
}
return
false
;
}
/**
* Configure current user session parameters
*
* @param array $request GET request parameters
* @param array $postdata POST data
*
* @return array|false
*/
private
function
configure
(
$request
,
$postdata
)
{
$result
=
array
();
foreach
(
$postdata
as
$key
=>
$value
)
{
switch
(
$key
)
{
case
'language'
:
if
(
preg_match
(
'/^[a-z]{2}_[A-Z]{2}$/'
,
$value
))
{
$_SESSION
[
'language'
]
=
$value
;
$result
[
$key
]
=
$value
;
}
break
;
}
}
return
$result
;
}
/* ======== Utility functions ======== */
/**
* Localization initialization.
*/
private
function
locale_init
()
{
$lang
=
'en_US'
;
// @TODO: read language of logged user in authenticate?
if
(!
empty
(
$_SESSION
[
'language'
]))
{
$lang
=
$_SESSION
[
'language'
];
}
$LANG
=
array
();
@
include
INSTALL_PATH
.
'/locale/en_US.php'
;
if
(
$lang
!=
'en_US'
&&
file_exists
(
INSTALL_PATH
.
"/locale/$lang.php"
))
{
@
include
INSTALL_PATH
.
"/locale/$lang.php"
;
}
setlocale
(
LC_ALL
,
$lang
.
'.utf8'
,
'en_US.utf8'
);
self
::
$translation
=
$LANG
;
}
/**
* Returns translation of defined label/message.
*
* @return string Translated string.
*/
public
static
function
translate
()
{
$args
=
func_get_args
();
if
(
is_array
(
$args
[
0
]))
{
$args
=
$args
[
0
];
}
$label
=
$args
[
0
];
if
(
isset
(
self
::
$translation
[
$label
]))
{
$content
=
trim
(
self
::
$translation
[
$label
]);
}
else
{
$content
=
$label
;
}
for
(
$i
=
1
,
$len
=
count
(
$args
);
$i
<
$len
;
$i
++)
{
$content
=
str_replace
(
'$'
.
$i
,
$args
[
$i
],
$content
);
}
return
$content
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Apr 4, 6:32 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822857
Default Alt Text
kolab_api_controller.php (16 KB)
Attached To
Mode
rWAP webadmin
Attached
Detach File
Event Timeline